去年看完的《图解java多线程设计模式》,可惜当时没做笔记,导致后来忘了许多东西,打算再温习下这本书,顺便在这里记录一下~

一、顺序执行、并行、并发

顺序执行:多个操作按照顺序依次执行。

并行:多个任务同时进行,同一时间内可以执行多个任务,这种方式,叫做并行执行,比如多核处理器,多个核可以同时处理多个任务。

并发:多个任务通过切分时间段,来达到“同时进行”的效果,比如单核处理器,在“同时”处理多个任务时,就会不停的切换来执行不同的任务,不可能有同一时间执行不同任务的情况。

下面引用别人的一句话来说明下并行和并发:

并发是两个任务可以在重叠的时间段内启动,运行和完成。并行是任务在同一时间运行,例如,在多核处理器上。 并发是独立执行过程的组合,而并行是同时执行(可能相关的)计算。 并发是一次处理很多事情,并行是同时做很多事情。

应用程序可以是并发的,但不是并行的,这意味着它可以同时处理多个任务,但是没有两个任务在同一时刻执行。

应用程序可以是并行的,但不是并发的,这意味着它同时处理多核CPU中的任务的多个子任务。

一个应用程序可以即不是并行的,也不是并发的,这意味着它一次一个地处理所有任务。

应用程序可以即是并行的也是并发的,这意味着它同时在多核CPU中同时处理多个任务。

二、synchronized修饰符

当我们说一个线程获得锁以后,则意味着这个线程可以执行当前对象(或类)里的synchronized方法,而且他线程则需要排队等待该线程释放锁以后才可能获得锁,进而执行锁里面的程序。

synchronized修饰后,存在对象锁和类锁两种类型。

2.1:对象锁


synchronized (this){
...略
}

2.2:类锁


synchronized (XXX.class){
...略
}

2.3:区别和作用域

对象锁指的是当前线程获得了某个实例的锁,假如有个Word类,有A、B两个同步方法,C属于普通方法,如图所示:

图1

可以发现,对象锁的作用域只针对当前对象生效,就像w1和w2里的A方法可以被不同的线程同时执行,但是同一个对象内的同步块,却只允许持有当前对象锁的线程执行,如t2、t3均被挡在了外面,当t1释放锁以后,t2、t3才会重新竞争锁,竞争到锁以后就会执行自己想要执行的同步逻辑。

类锁指的是当前线程获得了某个类的锁,还是Word类,有A、B两个static方法(静态方法属于类方法,加synchronized修饰符后等效于上面提到的synchronized(Word.class)),C属于普通static方法,如图所示:

图2

跟上面相比较,这里的t5受到了t1的影响,因为t1获得了Word类的锁,w1和w2共属一个类,因此t1获得类锁以后,其他线程想要访问这个类里的同步块,就得等到t1释放锁以后才可以继续竞争锁然后执行自己想要执行的同步逻辑。

三、线程间的通信

3.1:Wait

这几个方法是属于每个实例对象的,所有实例都拥有一个“等待队列”(虚拟概念,实例里并不存在该字段),它是在实例的wait方法调用后存放停止操作线程的队列。执行wait方法后,线程进入当前实例的“等待队列”,以下几种情况可以让线程退出“等待队列”:

①其他线程调用notify、notifyAll方法来将其唤醒

②其他线程调用interrupt来将其唤醒

③wait方法本身超时

当执行了下面的代码:


obj.wait();

我们可以说当前线程在obj上发生了等待,当前线程进入了obj的“等待队列”,此时当前线程会让出锁,让其他线程继续竞争获得该实例的锁(因此这里有个规则,调用wait的线程必须持有当前实例对象的锁

过程如下图:

图3

3.2:notify

现在先来介绍下notify,该方法会将等待队列里的线程取出,让其退出等待并参与锁竞争然后继续执行上次wait后没有执行完的语句。整体过程如下图所示:

图4

可以看到,t1在被挂起后,会因为t2调用了同实例的notify方法,而让t1被从等待队列里释放,重新加入到所得竞争力,t2执行完毕后释放锁,锁又再次被t1竞争到,t1将继续执行上次被挂起时后面未执行完的语句。

需要指出的是,如果等待队列里的线程是多个,那么被唤醒的那一个,将会是等待队列里所有线程随机的一个,不会特定哪一个线程会被唤起。

3.3:notifyAll

接下来介绍notifyAll方法,顾名思义,就是将等待队列里的线程全部唤起,然后这些线程将全部加入到锁竞争,竞争到,继续完成上次被挂起时未执行完毕的操作,流程图如下:

图5

说明,当线程调用实例的wait、notify、notifyAll方法有个大前提,就是必须要求该线程拥有该实例的锁,否则会抛IllegalMonitorStateException异常。

在编写程序时,是该选择notify还是选择notifyAll?这个可以指出的是,notifyAll往往更加健壮,而notify由于唤起的线程少,因此效率会更高,但是存在程序停止的风险。

附上使用wait、notify进行线程通信的例子:

利用ReentrantLock简单实现一个阻塞队列

java设计模式:简单实现生产者和消费者模式

[温故]图解java多线程设计模式(一)的更多相关文章

  1. [温故]图解java多线程设计模式(二)

    join & interrupt 这俩方法属于线程对象里的方法,属于线程本身的操作. join方法 用于等待一个线程的终止,等待期间将会阻塞,直到被等待的线程终止结束. 所以join可以用来做 ...

  2. 《图解Java多线程设计模式》读书笔记

    略读中...后面详读的时候,补充经典图片和文字说明

  3. 图解java多线程设计模式之一一synchronized实例方法体

    synchronized实例方法体和synchronized代码块 synchronied void method(){ ....... } 这个等同于下面将方法体用synchronized(this ...

  4. java多线程设计模式

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt220 java多线程设计模式 java语言已经内置了多线程支持,所有实现Ru ...

  5. Java多线程设计模式(一)

    目录(?)[-] Java多线程基础 Thread类的run方法和start方法 线程的启动 线程的暂时停在 线程的共享互斥 线程的协调 Single Threaded Execution Patte ...

  6. Java多线程设计模式(4)线程池模式

    前序: Thread-Per-Message Pattern,是一种对于每个命令或请求,都分配一个线程,由这个线程执行工作.它将“委托消息的一端”和“执行消息的一端”用两个不同的线程来实现.该线程模式 ...

  7. Java多线程设计模式(四)

    目录(?)[-] Future Pattern Two-Phase Termination Pattern Thread-Specific Storage Pattern Active Object ...

  8. Java多线程设计模式(三)

    目录(?)[-] Read-Wirte Lock Pattern Thread-Per-Message Pattern Worker Thread Pattern   Read-Wirte Lock ...

  9. Java多线程设计模式(二)

        目录(?)[-] Guarded Suspension Pattern Balking Pattern Producer-Consumer Pattern   Guarded Suspensi ...

随机推荐

  1. CentOS7防火墙firewall相关操作

    1.firewalld的基本使用 启动: systemctl start firewalld 查看状态: systemctl status firewalld 停止: systemctl disabl ...

  2. 455. Assign Cookies

    static int wing=[]() { std::ios::sync_with_stdio(false); cin.tie(NULL); ; }(); class Solution { publ ...

  3. mongo学习- 副本集 大多数原则

    副本集中有一个重要的概念“大多数”,意思是说,选择主节点需要大多数决定(本人亲自做了实验) 步骤: 1.开启副本集(如果没有配置好 副本集的 亲参考我的上篇文章  https://www.cnblog ...

  4. Linux设备驱动模型底层架构及组织方式

    1.什么是设备驱动模型? 设备驱动模型,说实话这个概念真的不好解释,他是一个比较抽象的概念,我在网上也是没有找到关于设备驱动模型的一个定义,那么今天就我所学.所了解 到的,我对设备驱动模型的一个理解: ...

  5. cin和gitchar的区别

    cin是iostream(输入输出类) 类下的istream(输入类)类的对象,作用是顺序输入字符串.cin.get()是cin的方法.cin.get()是C++面向对象的操作,getchar()是C ...

  6. webapi Model Validation 模型验证

    通常情况下,对于那些经常为别人提供数据接口的开发人员来说,对于调用方传递过来的参数都会有验证处理.例如: if (string.IsNullOrEmpty(entity.Name)) { //当姓名为 ...

  7. 用Swift实现一款天气预报APP(一)

    这个系列的目录: 用Swift实现一款天气预报APP(一) 用Swift实现一款天气预报APP(二) 用Swift实现一款天气预报APP(三) Swift作为现在苹果极力推广的语言,发展的非常快.这个 ...

  8. Elasticsearch 安装的时候,Unsupported major.minor version 51.0问题的解决

    Elasticsearch安装的时候报错 bootstrap/Elasticsearch : Unsupported major.minor version 51.0 网上一般说的方法是,升级或者降级 ...

  9. D3.js的基础部分之数组的处理 映射(v3版本)

    映射(Map)   映射(Map)是十分常见的一种数据结构,由一系列键(key)和值(value)组成的.每个key对应一个value,根据key可以获取和设定value,也可以根据key来查询val ...

  10. java 封装返回json数据

    做的东西,一直是用easyui的,和后台的交互数据都是json格式的. 今天想要单独弄一个json数据返回给前台,其实是比较简单的问题,json接触不多,记录一下. 代码: public static ...