(原)

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方法必需放在循环里面。像下面这样。

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

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

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

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

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

notify:

  1. Wakes up a single thread that is waiting on this object's monitor 唤醒一个在wait方法处等待的线程。
  1. The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object. 这个被唤醒的线程不会被执行,直到它得到了这个对象锁。
  1. The awakened thread will compete in the usual manner with any other threads that might be actively competing to synchronize on this object 被唤醒的线程将会与其它线程去竞争对象锁。(表示被唤醒不代表着马上会执行,除非该线程拿到对象锁。)
  1. Only one thread at a time can own an object's monitor.只有一个线程在这此时得到这个对象锁。
  2.  
  3. This method should only be called by a thread that is the owner of this object's monitor 这个方法需要被获得了对象锁的线程去调用。
    获取对象锁有三种方法:
  1. By executing a synchronized instance method of that object 执行了对象的同步方法。
  1. By executing the body of a {@code synchronized} statement that synchronizes on the object 执行了这个对象同步代码块。
  1. For objects of type {@code Class,} by executing a synchronized static method of that class.对于Class,执行了一个静态的synchronized方法(这表示锁住了class)。
  1. 最后解释一下关于下面这段代码,文档中为什么要我们用while,而不是if 或是不加判断之类的
  1. synchronized (obj) {
  2. while (<condition does not hold>)
  3. obj.wait(timeout);
  4. ... // Perform action appropriate to condition
  5. }

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

  1. if(num == 1){
  2. wait();
  3. }
  4.  
  5. num++;
  6.  
  7. 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那么这个线程不将继续等待。

  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. Chapter 4 Invitations——15

    He slouched off, back toward the school. 他无精打采的回去了学校. I heard a low chuckle. 我听到了低声的笑. Edward was wa ...

  2. TypeScript 素描 - 模块、命名空间

    /* 其实前面一些都是废话,因为都和C#类似.从模块开始就需要深入的去理解了 文档反复声明了 内部模块现在称做 命令空间 外部模块称为 模块 模块在其自身的作用域里执行,而不是在全局作用域里,也就是说 ...

  3. Asp.net Core 使用Jenkins + Dockor 实现持续集成、自动化部署(三):搭建jenkins集群环境

    写在前面 大家可以看到本文的配图,左边是jenkins单机环境,右边是jenkins集群.个中区别,不言而喻,形象生动. 前面我分别介绍了.net core 程序的多种部署方式(无绝对孰优孰劣): 1 ...

  4. leetcode — minimum-depth-of-binary-tree

    /** * Source : https://oj.leetcode.com/problems/minimum-depth-of-binary-tree/ * * * Given a binary t ...

  5. 新的一年,来看看大数据与AI的未来展望

    本文由云+社区发表 作者:堵俊平 在数据爆炸与智能革命的新时代,新的平台与应用层出不穷,开源项目推动了前沿技术和业界生态快速发展.本次分享将以技术和生态两大视角来看大数据和人工智能技术的发展,通过分析 ...

  6. 微服务实战(二):使用API Gateway

    微服务实战(一):微服务架构的优势与不足 微服务实战(二):使用API Gateway 微服务实战(三):深入微服务架构的进程间通信 微服务实战(四):服务发现的可行方案以及实践案例 微服务实践(五) ...

  7. 痞子衡嵌入式:ARM Cortex-M内核那些事(2)- 第一款微控制器

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是第一款Cortex-M微控制器. 1.天生荣耀:ARM Cortex-M处理器由来 ARM公司自2004年推出ARMv7内核架构时,摒弃 ...

  8. haproxy使用演示--技术流ken

    haproxy简介 HAProxy提供高可用性.负载均衡以及基于TCP和HTTP应用的代理,支持虚拟主机,它是免费.快速并且可靠的一种解决方案.基于合理的配置及优化,完全可以实现单机支持数 以万计的并 ...

  9. Django 系列博客(九)

    Django 系列博客(九) 前言 本篇博客介绍 Django 模板的导入与继承以及导入导入静态文件的几种方式. 模板导入 模板导入 语法:``{% include '模板名称' %} 如下: < ...

  10. javascript基础修炼(10)——VirtualDOM和基本DFS

    1. Virtual-DOM是什么 Virtual-DOM,即虚拟DOM树.浏览器在解析文件时,会将html文档转换为document对象,在浏览器环境中运行的脚本文件都可以获取到它,通过操作docu ...