(原)

JAVA多线程这一块有点绕,特别是对于锁,对锁机制理解不清的话,程序出现了问题也很难找到原因,在此记录一下线程的执行以及各种锁。

1、JAVA中,每个对象有且只有一把锁(lock),也叫监视器(monitor)。

2、同步(synchronized),synchronized可以修饰的方法或方法中的对象。

3、如果有一个线程进入到了synchronized方法修饰的对象,那么它将会获得这个对象的唯一一把锁,在该线程没有交出这把锁的时候,其它线程是无法访问到该方法中的。该线程会在执行完synchronized方法块中的内容后交出对象锁。

4、关于wait,notify,属于Object类,并且无法被重写,(网上JDK的1.5和1.6有中文版的API,对于这一块的翻译基本都是机器翻译,很不准确。建议看原版的英文说明文档)。

wait:

4.1、wait方法The current thread must own this object's monitor,当前线程必需获得这个对象的锁。因为一个线程进入了synchronized的代码块表示这个线程拿到了对象锁,那么这个wait方法必需在synchronized代码块中。

4.2、这个方法让进入到此处的线程丢掉对象锁并且挂起等待(能执行到wait方法的线程一定是拿到了对象锁的线程,如果不理解,请看4.1)。

4.3、其它线程调用这个对象的notify或notifyAll方法时,系统会在当前挂起等待在wait方法处的多个线程中,随机找出一个唤醒,被唤醒的线程会等待直到它拿到了对象锁并继续执行。

4.4、一个线程可能在通知、打断或超时之前被唤醒,这就是所谓的超时欺骗唤醒。实际情况下会很少出现这种情况,应用程序必需防范着判断条件使该线程被唤醒,如果条件不满足需要该线程继续等待。换句话说,wait方法必需放在循环里面。像下面这样。

synchronized (obj) {
while (<condition does not hold>)
obj.wait(timeout);
... // Perform action appropriate to condition
}
这句话即使看明白了,也有些难理解,画个图:
4.4.1、比如有线程1进到了synchronzied,拿到了对象锁,此时其它线程都无法进法该synchronized方法块中。

4.4.2、当线程1执行到wait方法时,会丢掉手上的锁,这时其它线程就能进来了,然后线程1会在此处挂起,不再执行,直到有其它线程调用了这个对象的notify或notifyAll方法。

4.4.3、此时线程2和线程3以同样的方法来到了wait方法处等待。

4.4.4、然后又来了一个线程4,进入了该对象的另一个方法,并且调用了该对象的notify方法。

4.4.5、对象notify被调用后,wait方法处等待的线程中有一个有机会被唤醒,得到锁并继续往下执行。其它线程依旧会在原处等待。

notify:

Wakes up a single thread that is waiting on this object's monitor 唤醒一个在wait方法处等待的线程。
The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object. 这个被唤醒的线程不会被执行,直到它得到了这个对象锁。
The awakened thread will compete in the usual manner with any other threads that might be actively competing to synchronize on this object 被唤醒的线程将会与其它线程去竞争对象锁。(表示被唤醒不代表着马上会执行,除非该线程拿到对象锁。)
Only one thread at a time can own an object's monitor.只有一个线程在这此时得到这个对象锁。

This method should only be called by a thread that is the owner of this object's monitor 这个方法需要被获得了对象锁的线程去调用。
获取对象锁有三种方法:
By executing a synchronized instance method of that object 执行了对象的同步方法。
By executing the body of a {@code synchronized} statement that synchronizes on the object 执行了这个对象同步代码块。
For objects of type {@code Class,} by executing a synchronized static method of that class.对于Class,执行了一个静态的synchronized方法(这表示锁住了class)。
最后解释一下关于下面这段代码,文档中为什么要我们用while,而不是if 或是不加判断之类的
synchronized (obj) {
while (<condition does not hold>)
obj.wait(timeout);
... // Perform action appropriate to condition
}

 在上面的例子中,如果这里的条件是

if(num == 1){
wait();
} num++; notify();

如果三个线程进到wait方法时num为0,

我需要num 为 1时,一直等待,直到它为0才能让num+1

线程2获得了锁,当它执行到notify方法时,num变成了1,此时如果线程1被唤醒得到对象锁后,应该是重新做判断num == 1,如果num为1,还是得继续等待挂起。

如果这里用的是if,那么它表示该线程1在进if 前是满足num ==1这个条件的,但是出if判断时却是不满足num ==1这个条件的。根据已知我需要num 为 1时,一直等待,所以这里的if判断是不对的。

如果这里换成while,那么当线程1被唤醒得到线程锁,它还是得重新做判断,如果num ==  1那么这个线程不将继续等待。

												

Java线程锁,synchronized、wait、notify详解的更多相关文章

  1. java线程池的使用与详解

    java线程池的使用与详解 [转载]本文转载自两篇博文:  1.Java并发编程:线程池的使用:http://www.cnblogs.com/dolphin0520/p/3932921.html   ...

  2. Java线程创建形式 Thread构造详解 多线程中篇(五)

    Thread作为线程的抽象,Thread的实例用于描述线程,对线程的操纵,就是对Thread实例对象的管理与控制. 创建一个线程这个问题,也就转换为如何构造一个正确的Thread对象. 构造方法列表 ...

  3. Java线程池七个参数详解

    Java多线程开发时,常常用到线程池技术,这篇文章是对创建java线程池时的七个参数的详细解释. 从源码中可以看出,线程池的构造函数有7个参数,分别是corePoolSize.maximumPoolS ...

  4. Java线程池(ThreadPool)详解

    线程五个状态(生命周期): 线程运行时间 假设一个服务器完成一项任务所需时间为:T1 创建线程时间,T2 在线程中执行任务的时间,T3 销毁线程时间.    如果:T1 + T3 远大于 T2,则可以 ...

  5. 关于java线程锁synchronized修饰普通方法与静态方法的区别

    最近研究线程方面问题,关于这个synchronized锁修饰的问题,先是修饰普通方法,然后通过两个线程,各自执行自己对象的锁,发现方法执行互不影响,代码如下: private static int n ...

  6. Java精通并发-synchronized关键字原理详解

    关于synchronized关键字原理其实在当时JVM的学习[https://www.cnblogs.com/webor2006/p/9595300.html]中已经剖析过了,这里从研究并发专题的角度 ...

  7. java线程池ThreadPoolExecutor类使用详解

    在<阿里巴巴java开发手册>中指出了线程资源必须通过线程池提供,不允许在应用中自行显示的创建线程,这样一方面是线程的创建更加规范,可以合理控制开辟线程的数量:另一方面线程的细节管理交给线 ...

  8. Java线程的五种状态详解

    状态转换图 1.new状态:通过new关键字创建了Thread或其子类的对象 2.Runnable状态:即就绪状态.可从三种状态到达,new状态的Thread对象调用start()方法,Running ...

  9. java线程基础知识----SecurityManager类详解

    在查看java Thread源码的时候发现一个类----securityManager,虽然很早就知道存在这样一个类但是都没有深究,今天查看了它的api和源码,发现这个类功能强大,可以做很多权限控制策 ...

  10. 【多线程】Java线程池七个参数详解

    /** * Creates a new {@code ThreadPoolExecutor} with the given initial * parameters. * * @param coreP ...

随机推荐

  1. Android--调用系统照相机拍照与摄像

    前言 在很多场景中,都需要用到摄像头去拍摄照片或视频,在照片或视频的基础之上进行处理.但是Android系统源码是开源的,很多设备厂商均可使用,并且定制比较混乱.一般而言,在需要用到摄像头拍照或摄像的 ...

  2. js如何使用正则表达式实现过滤HTML标签?(/<[^<>]+>/g)

    js如何使用正则表达式实现过滤HTML标签?(/<[^<>]+>/g) 一.总结 js进阶正则表达式实现过滤HTML标签(<>标签中不能包含标签实现过滤HTML标签 ...

  3. [PHP] 适配器模式的日常使用

    适配器模式就是将一个类的接口方法转换成我希望用的另一个方法 , 下面是个常见的用处 class Session{ public $mc; public function __construct(){ ...

  4. Excel读写

    http://www.cnblogs.com/mingforyou/archive/2013/08/26/3282922.html 读Excel代码如下: import java.io.File;im ...

  5. react 源码之setState

    今天看了react源码,仅以记录. 1:monorepo (react 的代码管理方式) 与multirepo 相对. monorepo是单代码仓库, 是把所有相关项目都集中在一个代码仓库中,每个mo ...

  6. PHP实现微信随机红包算法和微信红包的架构设计简介

    微信红包的架构设计简介: 原文:https://www.zybuluo.com/yulin718/note/93148 @来源于QCon某高可用架构群整理,整理朱玉华. 背景:有某个朋友在朋友圈咨询微 ...

  7. 一个可以自动生成css样式的插件happycss

    一直在页面写css, 重复写着样式,发现布局中,特别是h5,大量的样式都是margin,padding,width,height, 而,当我们需要给一个标签写样式的时候,避免内联样式,我们又需要取cl ...

  8. vue从入门到进阶:Vuex状态管理(十)

    Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化. 在 Vue 之后引入 vuex 会进行自动 ...

  9. C#监控指定目录的文件变化的代码

    如下的资料是关于C#监控指定目录的文件变化的代码. FileSystemWatcher watcher = new FileSystemWatcher();watcher.Path = @" ...

  10. 从Linux上传到Git过程

    1.1 实验内容 本次课程讲的是在实验楼的在线环境中,如何使用 Github 去管理在在线环境中使用的代码.配置.资源等实验相关文件,怎样去添加.同步和下拉在远程仓库中的实验文件,以此来维持自身的实验 ...