并发与多线程

并发

  并发(concurrency)是指CPU在某个时间段内交替处理多任务的能力。每个CPU不可能只顾着执行某个进程,而让其他进程一直等待被执行。所以,CPU把可执行时间均分成若干份,每个进程执行一份或多份时间后,记录当前的工作状态,释放相关资源并进入等待状态,让其他进程抢占CPU等资源。

  在并发环境下,由于程序的封闭性被打破,出现了以下特点:

  1.并发程序之间有相互制约的关系。直接制约体现在一个程序需要另一个程序的计算结果;间接制约体现在多个进程竞争共享资源。

  2.并发程序的执行过程是断断续续的。程序需要保留现场,记忆现场指令及执行点。

  3.当并发数设置合理并且CPU拥有足够的处理能力时,并发会提高程序的运行效率。

  在Java编程中,并发主要与线程有关。

线程

  线程是CPU调度和分派的基本单位,为了更充分地利用CPU资源,一般都会使用多线程进行处理。多线程的作用是提高任务的平均执行速度,但是会导致程序可解性变差,编程难度加大。所以,合适的线程数才能让CPU资源被充分利用。

  每一个线程都有自己的操作栈、程序计数器、局部变量表等资源。同一进程内的所有线程都可以共享该进程的所有资源。

  Java提供了两种形式定义线程类:

  1.实现Runnable接口并重写其中的run()方法。

 1 class Consumer implements Runnable {
 2 
 3     private Store store;
 4 
 5     public Consumer(Store store) {
 6         this.store = store;
 7     }
 8 
 9     @Override
10     public void run() {
11         for (int i = 0; i < 1000; i++) {
12             store.getValue();
13         }
14     }
15 
16 }
Consumer

  2.继承Thread类并重写其中的run()方法。

 1 class Producer extends Thread {
 2 
 3     private Store store;
 4 
 5     public Producer(Store store) {
 6         this.store = store;
 7     }
 8 
 9     @Override
10     public void run() {
11         for (int i = 0; i < 1000; i++) {
12             store.setValue((int) (Math.random() * 100));
13         }
14     }
15 
16 }
Producer

  里氏代换原则对继承的一个约束是子类不重写父类的非抽象方法,而Thread类的run()方法不是一个抽象方法,所以继承Thread类并重写其中的run()方法就不符合里氏代换原则,该方式不推荐使用。相比之下,实现Runnable接口可以使编程更加灵活,对外暴露的细节也比较少,让使用者专注于实现线程的run()方法。

线程状态

  线程的生命周期分为以下5种状态:

新建状态

  新建状态是线程被创建且未启动的状态。也就是说,初始化一个线程对象时,该对象进入新建状态。

  线程对象的初始化分为2种:

  1.如果是继承Thread类的线程类,则该类线程对象可以直接通过new运算进行初始化。

  2.如果是实现Runnable接口的线程类,则该类线程对象通过new运算进行初始化后需要包装为一个Thread对象。

就绪状态

  就绪状态是线程启动后运行之前的状态。即启动了的线程在准备执行run()方法时的状态。

  线程的启动是指线程对象调用Thread的start()方法。

运行状态

  运行状态是线程运行时的状态,即启动了的线程在执行run()方法时的状态。

阻塞状态

  阻塞状态分以下3种情况:

  同步阻塞:缺少资源无法继续运行。抢占到资源后会退出该状态。

  主动阻塞:主动让出CPU执行权,即线程执行Thread的sleep()方法之后的状态。调用sleep()方法时会传入一个long类型的参数,表示睡眠的时间,单位为毫秒,时间结束时会退出该状态。

  等待阻塞:进入睡眠,即线程执行Object的wait()方法之后的状态。其他线程执行Object的notify()方法或notifyAll()方法之后会退出该状态。

终止状态

  终止状态是线程执行结束或因异常退出后的状态。

线程同步

  线程同步机制的主要任务是,对多个相关线程在执行次序上进行协调,使并发执行的每个线程之间能按照一定的时序共享资源,并能很好地相互合作,从而使程序的执行具有可再现性。

  资源的共享分为两种方式:

  互斥共享方式:某些资源例如打印机、磁带机等,一次只能给一个线程使用,当一个线程申请该资源时,如果该资源有其他线程在使用,则该线程需要等待,直到资源被释放之后才能申请。

  同时访问方式:某些资源例如磁盘设备等,一次可以给多个线程“同时”访问,这种“同时”是宏观上的,实际上还是多个线程交替访问。

  临界资源指的是一段时间内只能由一个线程访问的资源,而临界区指的是每个线程中访问临界资源的那部分代码。显然,若能保证每个线程互斥地进入自己的临界区,便可以实现每个线程对临界资源的互斥访问。为此,需要在每个线程进入临界区前需要对访问的临界资源进行检查,如果它是空闲的,则进入临界区;否则等待,直到临界资源空闲。具体流程如下:

  进入区:检查临界资源的状态,如果空闲,则将其状态改为被访问,并进入临界区;如果被访问,则循环等待,直到其状态变为空闲。

  临界区:访问临界资源。

  退出区:将临界资源的状态改为空闲,并释放临界资源。

  Java提供synchronized关键字标识方法或代码块,被标识的方法称为同步方法,被标识的代码块称为同步代码块。每个对象都有一个监视器与之关联。当线程通过该对象执行同步方法或同步代码块时,它首先试图获取监视器,如果获取到监视器,则锁定该对象,防止其他线程通过该对象执行同步方法或同步代码块,执行结束后,解锁该对象并释放监视器;如果获取不到监视器,表示有其他线程通过该对象执行同步方法或同步代码块,则会进入等待。所以,监视器的作用就相当于进入区和退出区的作用。

  例如:定义两种线程——生产者(Producer)和消费者(Consumer),生产者每次会产生一个数,消费者每次会取出一个数。Producer和Consumer线程对象通过同一个Store对象来调用Store的同步方法。

 1 class Store {
 2 
 3     private int value;
 4 
 5     public synchronized int getValue() {
 6         System.out.println("-取出" + value);
 7         return value;
 8     }
 9 
10     public synchronized void setValue(int value) {
11         this.value = value;
12         System.out.println("放入" + value);
13     }
14 
15 }
Store
1 @Test
2 void test() {
3     Store store = new Store();
4     Thread producer = new Producer(store);   // 继承Thread类的线程类对象的初始化
5     Thread consumer = new Thread(new Consumer(store));   // 实现Runnable接口的线程类对象的初始化
6     producer.start();
7     consumer.start();
8 }
test

  部分输出结果:

  

  当Consumer线程对象调用getValue()方法时,会获取监视器,锁定Store对象,直到方法返回后解锁Store对象,释放监视器;当Producer线程对象调用setValue()方法时也是如此。所以在创建Producer和Consumer线程对象时需要传入同一个Store对象。如果传入不同的Store对象,每一个Store对象都有一个监视器,则起不到锁定的效果。

  根据输出结果可以发现:取出多次数后才放入一次数,放入多次数后才取出一次数。要实现放入一个数后取出一个数的效果,则需要添加一个标识量。

  改进:在Store类中添加一个mutex标识量,当mutex为true时,表示Store内存了一个数,等待Consumer来取;为false时,表示Store内没有数,等待Producer生产数。

 1 class Store {
 2 
 3     private int value;
 4     private boolean mutex;   // mutex初始值为false,表示没有数
 5 
 6     public synchronized int getValue() {
 7         while (! mutex) {   // mutex为false时进入等待
 8             try {
 9                 wait();
10             } catch (InterruptedException e) {
11                 e.printStackTrace();
12             }
13         }
14         System.out.println("-取出" + value);
15         mutex = false;   // 取出数后将mutex置为false
16         notify();
17         return value;
18     }
19 
20     public synchronized void setValue(int value) {
21         while (mutex) {   // mutex为true时进入等待
22             try {
23                 wait();
24             } catch (InterruptedException e) {
25                 e.printStackTrace();
26             }
27         }
28         this.value = value;
29         System.out.println("放入" + value);
30         mutex = true;   // 放入数后将mutex置为true
31         notify();
32     }
33 
34 }
Store

  部分输出结果:

  

转载于:https://www.cnblogs.com/lqkStudy/p/11135153.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/247638.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

synchronize原理

synchronized的三种应用方式 一. 修饰实例方法&#xff0c;作用于当前实例加锁&#xff0c;进入同步代码前要获得当前实例的锁。 二. 修饰静态方法&#xff0c;作用于当前类对象加锁&#xff0c;进入同步代码前要获得当前类对象的锁。 三. 修饰代码块&#xff0c;指定加锁对象&…

不能修改“System Roots”钥匙串

iOS mac添加证书 不能修改“System Roots”钥匙串错误 如图&#xff1a; 解决方式&#xff1a; 打开钥匙串---登录---&#xff0c;直接把证书拖过来 然后&#xff0c;查看--我的证书&#xff0c;里面&#xff0c;找到证书&#xff0c;即可

未来产品的设计

Donald A. Norman继《情感化设计》之后&#xff0c;又一设计精品力作&#xff1a; 未来产品的设计样章试读及本书预定&#xff1a;http://www.china-pub.com/195642市场价 &#xff1a;&#xffe5;39.00 会员价 &#xff1a; &#xffe5;29.25(75折) 【作  者】(美)Donald…

css之字体图标

SVG与字体图标 SVG图片是矢量图片&#xff0c;不会随着图片的伸缩而影响质量&#xff0c;通常把只有一种颜色的图标做成SVG&#xff0c;通过SVG生成字体图标&#xff0c;放到项目中使用。 https://icomoon.io/是一个比较快捷的生成字体图标的线上工具&#xff0c;进入主页后&…

研发阶段模拟接口数据

因为在vue-cli工程中需要创建很多.vue文件&#xff0c;我们希望创建vue文件和创建html、css、js文件一样右键即可选择创建&#xff0c;并且创建的文件中可预先写好模板代码。 webstorm-Preferences打开选项界面 选择File and Code Templates&#xff0c;点击绿色加号 填…

真实项目中 ThreadLocal 的妙用

一、什么是 ThreadLocal ThreadLocal 提供了线程的局部变量&#xff0c;每个线程都可以通过 set() 和 get() 来对这个局部变量进行操作&#xff0c;但不会和其他线程的局部变量冲突&#xff0c;实现了线程间的据隔离。 简单讲&#xff1a;一个获取用户的请求线程 A&#xff0c;…

css之flex布局

flex布局是css3中的重要布局方式&#xff0c;称为“弹性布局”&#xff0c;每次想到它主要是遇到元素垂直居中、元素宽高自适应的问题&#xff0c;这些问题在flex中都能过简单设置就解决&#xff0c;它更像是原生APP中的布局操作&#xff0c;布局不必写N多的盒模型代码来实现&a…

javascript对URL中的参数进行简单加密处理

javascript的api本来就支持Base64&#xff0c;因此我们可以很方便的来进行编码和解码。 var encodeData window.btoa("namexiaoming&age10")//编码 var decodeData window.atob(encodeData)//解码。 下面来个具体的例子来说明如何对url中参数进行转码&#xff…

HTML元素title里面如何换行

在调试代码的时候我就遇到一个问题&#xff0c;HTML元素title里面通常只显示一行&#xff0c;那我想要他换行&#xff0c;就是多行显示&#xff0c;如何实现&#xff1f;JS代码里面比如Alert里面又该如何换行&#xff1f; 经过我的一番实验 要实现这种效果有几种方法&#xff0…

div内图片和文字水平垂直居中

大小不固定的图片、多行文字的水平垂直居中 本文综述 想必写css的都知道如何让单行文字在高度固定的容器内垂直居中&#xff0c;但是您知道或者想过让行数不固定的文字在高度固定的容器内垂直居中呢&#xff1f;本文将会告诉你如何实现多行文字的垂直居中显示。 关于图片垂直居…

敏友的【敏捷个人】有感(3): 有感于“敏捷个人”讨论与练习

2010年我对个人管理进行了自己的一些思考&#xff0c;在2011年提出敏捷个人概念&#xff0c;并且在线上、线下进行了多次交流&#xff0c;在一些大会上也做过分享。现在&#xff0c;已经有很 多IT和非IT的敏友们知道并在践行敏捷个人&#xff0c;帮助自己更快的成长。我收到大家…

jQuery编写插件

引言&#xff1a; 在项目中不同页面经常要用到已经写好的交互&#xff0c;比如弹窗&#xff0c;比如下拉菜单&#xff0c;比如选项卡&#xff0c;比如删除... 此时如果每次都把代码copy一份无疑是一件比较麻烦并且无趣的事情&#xff0c;而且个人认为有些low了&#xff0c;我们…

webstorm中nodejs代码提示

preferences->languages&frameworks->Node.js and Npm中选择一个本地的node版本 preferences->languages&frameworks->JavaScript->Libraries 勾选node.js Core 回到代码

Array.prototype.slice.call(arguments)

Array.prototype.slice.call(arguments)能将具有length属性的对象转成数组&#xff0c;除了IE下的节点集合&#xff08;因为ie下的dom对象是以com对象的形式实现的&#xff0c;js对象与com对象不能进行转换&#xff09;如&#xff1a;1 var a{length:2,0:first,1:second}; 2 Ar…

nodejs常用模块-url

URL nodejs中针对url的常用方法。 node下打印url&#xff0c;结果&#xff1a; 引入url模块 var url require(url) 1、parse方法 将url解析成对象&#xff0c;parse方法原型&#xff1a; url.parse(urlStr[, parseQueryString][, slashesDenoteHost]) 可传递三个参数…

常用的javascript设计模式

请坚持 什么是设计模式 百度百科&#xff1a; 设计模式&#xff08;Design pattern&#xff09;是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。 使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 毫无疑问&#xff0c;设计模式…

iOS警告-This block declaration is not a prototype

关于警告 我们定义一个不带参数的block,通常是如下的方式 1typedefvoid (^UpdateSwichBtnBlock)();在xcode9中会提示一个警告 12This block declaration is not a prototypeInsert ‘void解决方式可以是如下的几种 1typedefvoid (^UpdateSwichBtnBlock)(void);但是这样,很多第三…

mongoose操作mongodb

http://mongoosejs.com/docs/api.html#index-js mongoose是nodejs环境下操作mongodb的模块封装&#xff0c;使用mongoose之后&#xff0c;实际上只需要在mongodb中创建好数据库与用户&#xff0c;集合的定义、创建、操作等直接使用mongoose即可。 一、连接二、重要概念三、基本…

mac下iterm配色、半透明与样式设置

主要为了实现命令行颜色高亮与整个命令窗口半透明效果。 1、配色主题包下载 1、http://iterm2colorschemes.com/ 下载后解压&#xff0c;到iterm2中&#xff0c;左上角iTerm2->preferences->Profiles&#xff0c;右侧面板找到Colors选项&#xff0c;右下角展开Color Pr…

一个 Dubbo 服务启动要两个小时

前几天在测试环境碰到一个非常奇怪的与 dubbo 相关的问题&#xff0c;事后我在网上搜索了一圈并没有发现类似的帖子或文章&#xff0c;于是便有了这篇。 希望对还未碰到或正在碰到的朋友有所帮助。 现象 现象是这样的&#xff0c;有一天测试在测试环境重新部署一个 dubbo 应用的…