目录

一、概述

二、Lock接口

三、线程间的通信

解决虚假唤醒问题

Lock通信示例:

四、线程间定制化通信


一、概述

JUC就是java.util.concurrent工具包的简称,这是一个处理线程的工具包,JDK1.5开始出现的。

管程:又称Monitor监视器,又是锁:是一种同步的机制,保证同一时间,只有一个线程访问被保护的数据或代码。

用户线程:自定义线程基本都是用户线程。通过Thread.currentThread().isDaemon()来判断是否是用户线程,等于 false是用户线程。等于true 是守护线程。

守护线程:特殊线程,运行在后台,比如:垃圾回收

设置守护线程:  线程.setDaemon(true); 在执行start()之前设置。

1、主线程结束了,用户线程还在运行,jvm存活。

2、没有用户线程了,都是守护线程,jvm结束。

二、Lock接口

Lock中常用方法:
1.void lock():获取锁。
2.void lockInterruptibly():如果当前线程未被中断,则获取锁。
3.Condition newCondition():返回绑定到此 Lock 实例的新 Condition 实例。
4.boolean tryLock():仅在调用时锁为空闲状态才获取该锁。
5.boolean tryLock(long time, TimeUnit unit):如果锁在给定的等待时间内空闲,
并且当前线程未被中断,则获取锁。
6.void unlock():释放锁。
Condition接口
//@since 1.5
public interface Condition {Condition接口中常用方法
1.void await():造成当前线程在接到信号或被中断之前一直处于等待状态。
2.boolean await(long time, TimeUnit unit):造成当前线程在接到信号、被中断或到达指定
等待时间之前一直处于等待状态。
3.long awaitNanos(long nanosTimeout):造成当前线程在接到信号、被中断或到达指定等待时
间之前一直处于等待状态。
4.void awaitUninterruptibly():造成当前线程在接到信号之前一直处于等待状态。
5.boolean awaitUntil(Date deadline):造成当前线程在接到信号、被中断或到达指定最后期
限之前一直处于等待状态。
6.void signal():唤醒一个等待线程。
7.void signalAll():唤醒所有等待线程。

面试题:Lock与Synchronized的区别?用新的Lock有什么好处?举例说说?

Lock不是Java语言内置的,Synchronized是Java语言的关键字,因此是内置特性。

Synchronized不需要用户手动释放锁,当Synchronized方法或者Synchronized代码块执行完之后,系统会自动让线程释放对锁的占用,而Lock则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁的现象。

1、原始构成

synchronized是关键字属于JVM层面,monitorenter(底层是通过monitor对象来完成,其实wait/notify等方法也依赖于monitor对象只有在同步块或方法中才能调wait/notify等方法)

monitorexit

Lock是具体类(java.util.concurrent.Locks.Lock)是api层面的锁。

2、使用方法

synchronized不需要用户去手动释放锁,当synchronized代码执行完成后系统会自动让线程释放对锁的占用

ReentrantLock则需要用户去手动释放锁,若没有主动释放锁,就有可能导致出现死锁现象

3、等待是否可中断

synchronized不可中断,除非抛出异常或者正常运行完成

ReentrantLock可中断,1.设置超时方法tryLock(long timeout,TimeUnit unit)

2.lockInterruptibly()放代码块中,调用interrupt()方法可中断

4、加锁是否公平

synchronized非公平锁

ReentrantLock两者都可以,默认非公平锁

5、锁绑定多个条件Condition

synchronized没有

ReentrantLock用来实现分组唤醒需要唤醒的线程们,可以精确唤醒,而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程

示例:

import java.util.concurrent.locks.ReentrantLock;public class LockSaleTicket {public static void main(String[] args) {LockTicket lockTicket = new LockTicket();new Thread(()-> {for (int i = 0; i < 40; i++) {lockTicket.sale();}},"aa").start();new Thread(()-> {for (int i = 0; i < 40; i++) {lockTicket.sale();}},"bb").start();new Thread(()-> {for (int i = 0; i < 40; i++) {lockTicket.sale();}},"cc").start();}}class LockTicket{private int number = 30;private final ReentrantLock lock = new ReentrantLock();//卖票方法public void sale() {lock.lock();try {if (number >0) {System.out.println(Thread.currentThread().getName() + ":卖出" + (number--)+" 剩余:"+number);}} finally {lock.unlock();}}}

三、线程间的通信

/*** 线程通信的例子:有2个线程实现对一个初始值是0的变量*         一个线程对值+1、一个线程对值-1*         A线程  1          B线程  0 *        A线程  1          B线程  0 *        A线程  1          B线程  0 *        ....*/
class Share{//初始值private int number = 0;//+1方法public synchronized void add() throws InterruptedException {if (number != 0) {//number不是0,等待wait();}number++;//number值是0就+1System.out.println(Thread.currentThread().getName() + " :: " + number);notifyAll();}//-1方法public synchronized void subtract() throws InterruptedException {if (number != 1) {//number不是1,等待wait();}number--;//number值是1就-1System.out.println(Thread.currentThread().getName() + " :: " + number);notifyAll();}}public class ThreadDemo1 {public static void main(String[] args) {Share share = new Share();new Thread(()-> {for (int i = 0; i <= 10; i++) {try {share.add();} catch (InterruptedException e) {e.printStackTrace();}}},"A").start();new Thread(()-> {for (int i = 0; i <= 10; i++) {try {share.subtract();} catch (InterruptedException e) {e.printStackTrace();}}},"B").start();}}

结果:

A :: 1
B :: 0
A :: 1
B :: 0
A :: 1
B :: 0
A :: 1
B :: 0
A :: 1
B :: 0
A :: 1
B :: 0
A :: 1
B :: 0
A :: 1
B :: 0
A :: 1
B :: 0
A :: 1
B :: 0
A :: 1
B :: 0

上面示例如果再增加2个线程一个+1,一个-1.结果还是正确的吗?

/*** 线程通信的例子:有2个线程实现对一个初始值是0的变量*         一个线程对值+1、一个线程对值-1*         A线程  1          B线程  0 *        A线程  1          B线程  0 *        A线程  1          B线程  0 *        ....*/
class Share{//初始值private int number = 0;//+1方法public synchronized void add() throws InterruptedException {if (number != 0) {//number不是0,等待wait();}number++;//number值是0就+1System.out.println(Thread.currentThread().getName() + " :: " + number);notifyAll();}//-1方法public synchronized void subtract() throws InterruptedException {if (number != 1) {//number不是1,等待wait();}number--;//number值是1就-1System.out.println(Thread.currentThread().getName() + " :: " + number);notifyAll();}}public class ThreadDemo1 {public static void main(String[] args) {Share share = new Share();new Thread(()-> {for (int i = 0; i <= 10; i++) {try {share.add();} catch (InterruptedException e) {e.printStackTrace();}}},"A").start();new Thread(()-> {for (int i = 0; i <= 10; i++) {try {share.subtract();} catch (InterruptedException e) {e.printStackTrace();}}},"B").start();new Thread(()-> {for (int i = 0; i <= 10; i++) {try {share.add();} catch (InterruptedException e) {e.printStackTrace();}}},"C").start();new Thread(()-> {for (int i = 0; i <= 10; i++) {try {share.subtract();} catch (InterruptedException e) {e.printStackTrace();}}},"D").start();}}

结果:

A :: 1
B :: 0
A :: 1
B :: 0
A :: 1
B :: 0
A :: 1
B :: 0
A :: 1
B :: 0
A :: 1
B :: 0
A :: 1
B :: 0
C :: 1
A :: 2
C :: 3
B :: 2
C :: 3
A :: 4
C :: 5
B :: 4
C :: 5
A :: 6
C :: 7
D :: 6
B :: 5
D :: 4
C :: 5
A :: 6
C :: 7
D :: 6
B :: 5
D :: 4
C :: 5
D :: 4
C :: 5
D :: 4
C :: 5
D :: 4

结果和预期结果不符。原因是虚假唤醒问题。

解决虚假唤醒问题

wait()在哪里睡,就在哪里醒

解决方式:把if判断换成while判断,等线程醒来之后会继续进行判断,不满足条件继续睡,直到满足条件继续往下执行。

/*** 线程通信的例子:有2个线程实现对一个初始值是0的变量*         一个线程对值+1、一个线程对值-1*         A线程  1          B线程  0 *        A线程  1          B线程  0 *        A线程  1          B线程  0 *        ....*/
class Share{//初始值private int number = 0;//+1方法public synchronized void add() throws InterruptedException {while (number != 0) {//number不是0,等待wait();}number++;//number值是0就+1System.out.println(Thread.currentThread().getName() + " :: " + number);notifyAll();}//-1方法public synchronized void subtract() throws InterruptedException {while (number != 1) {//number不是1,等待wait();}number--;//number值是1就-1System.out.println(Thread.currentThread().getName() + " :: " + number);notifyAll();}}public class ThreadDemo1 {public static void main(String[] args) {Share share = new Share();new Thread(()-> {for (int i = 0; i <= 10; i++) {try {share.add();} catch (InterruptedException e) {e.printStackTrace();}}},"A").start();new Thread(()-> {for (int i = 0; i <= 10; i++) {try {share.subtract();} catch (InterruptedException e) {e.printStackTrace();}}},"B").start();new Thread(()-> {for (int i = 0; i <= 10; i++) {try {share.add();} catch (InterruptedException e) {e.printStackTrace();}}},"C").start();new Thread(()-> {for (int i = 0; i <= 10; i++) {try {share.subtract();} catch (InterruptedException e) {e.printStackTrace();}}},"D").start();}}

结果:

A :: 1
B :: 0
A :: 1
B :: 0
A :: 1
B :: 0
A :: 1
B :: 0
A :: 1
B :: 0
C :: 1
B :: 0
A :: 1
B :: 0
C :: 1
B :: 0
A :: 1
B :: 0
C :: 1
D :: 0
A :: 1
B :: 0
C :: 1
D :: 0
A :: 1
B :: 0
C :: 1
D :: 0
A :: 1
D :: 0
C :: 1
D :: 0
A :: 1
D :: 0
C :: 1
D :: 0
C :: 1
D :: 0
C :: 1
D :: 0
C :: 1
D :: 0
C :: 1
D :: 0

Lock通信示例:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** 线程通信的例子:有2个线程实现对一个初始值是0的变量*        一个线程对值+1、一个线程对值-1*         A线程  1          B线程  0 *        A线程  1          B线程  0 *        A线程  1          B线程  0 *        ....*/
class Share{private final Lock lock = new ReentrantLock();private final Condition condition  = lock.newCondition(); //初始值private int number = 0;//+1方法public void add() throws InterruptedException {lock.lock();try {while (number != 0) {//number不是0,等待condition.await();}number++;//number值是0就+1System.out.println(Thread.currentThread().getName() + " :: " + number);condition.signalAll();} finally {lock.unlock();}}//-1方法public void subtract() throws InterruptedException {lock.lock();try {while (number != 1) {//number不是1,等待condition.await();}number--;//number值是1就-1System.out.println(Thread.currentThread().getName() + " :: " + number);condition.signalAll();} finally {lock.unlock();}}}public class ThreadDemo2 {public static void main(String[] args) {Share share = new Share();new Thread(()-> {for (int i = 0; i <= 10; i++) {try {share.add();} catch (InterruptedException e) {e.printStackTrace();}}},"A").start();new Thread(()-> {for (int i = 0; i <= 10; i++) {try {share.subtract();} catch (InterruptedException e) {e.printStackTrace();}}},"B").start();new Thread(()-> {for (int i = 0; i <= 10; i++) {try {share.add();} catch (InterruptedException e) {e.printStackTrace();}}},"C").start();new Thread(()-> {for (int i = 0; i <= 10; i++) {try {share.subtract();} catch (InterruptedException e) {e.printStackTrace();}}},"D").start();}}

结果:

A :: 1
B :: 0
A :: 1
B :: 0
A :: 1
B :: 0
A :: 1
B :: 0
A :: 1
B :: 0
A :: 1
B :: 0
A :: 1
B :: 0
A :: 1
B :: 0
A :: 1
B :: 0
A :: 1
B :: 0
A :: 1
B :: 0
C :: 1
D :: 0
C :: 1
D :: 0
C :: 1
D :: 0
C :: 1
D :: 0
C :: 1
D :: 0
C :: 1
D :: 0
C :: 1
D :: 0
C :: 1
D :: 0
C :: 1
D :: 0
C :: 1
D :: 0
C :: 1
D :: 0

四、线程间定制化通信

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;/*** 线程间定制化通信的例子:* 有3个线程,按照如下进行打印* A线程  打印2次     B线程  打印3次  C线程  打印5次 * A线程  打印2次    B线程  打印3次  C线程  打印5次 * A线程  打印2次    B线程  打印3次  C线程  打印5次 *      ....* 打印5轮*/
class ShareResource{private int flag = 1;//1:A、2:B、3:Cprivate final Lock lock = new ReentrantLock();private final Condition c1  = lock.newCondition(); private final Condition c2  = lock.newCondition(); private final Condition c3  = lock.newCondition(); //打印2次public void print2(int loop) throws InterruptedException {lock.lock();try {while (flag != 1) {//flag不是1,等待c1.await();}for (int i = 1; i <=2; i++) {System.out.println(Thread.currentThread().getName() + " :: "+ i +" 轮数:"+ loop);}flag=2;c2.signal();} finally {lock.unlock();}}//打印3次public void print3(int loop) throws InterruptedException {lock.lock();try {while (flag != 2) {//flag不是2,等待c2.await();}for (int i = 1; i <=3; i++) {System.out.println(Thread.currentThread().getName() + " :: "+ i +" 轮数:"+ loop);}flag=3;c3.signal();} finally {lock.unlock();}}//打印5次public void print5(int loop) throws InterruptedException {lock.lock();try {while (flag != 3) {//flag不是3,等待c3.await();}for (int i = 1; i <=5; i++) {System.out.println(Thread.currentThread().getName() + " :: "+ i +" 轮数:"+ loop);}flag=1;c1.signal();} finally {lock.unlock();}}
}
public class ThreadDemo3 {public static void main(String[] args) {ShareResource share = new ShareResource();new Thread(()-> {for (int i = 1; i <= 5; i++) {try {share.print2(i);} catch (InterruptedException e) {e.printStackTrace();}}},"A").start();new Thread(()-> {for (int i = 1; i <= 5; i++) {try {share.print3(i);} catch (InterruptedException e) {e.printStackTrace();}}},"B").start();new Thread(()-> {for (int i = 1; i <= 5; i++) {try {share.print5(i);} catch (InterruptedException e) {e.printStackTrace();}}},"C").start();}
}

结果:

A :: 1 轮数:1
A :: 2 轮数:1
B :: 1 轮数:1
B :: 2 轮数:1
B :: 3 轮数:1
C :: 1 轮数:1
C :: 2 轮数:1
C :: 3 轮数:1
C :: 4 轮数:1
C :: 5 轮数:1
A :: 1 轮数:2
A :: 2 轮数:2
B :: 1 轮数:2
B :: 2 轮数:2
B :: 3 轮数:2
C :: 1 轮数:2
C :: 2 轮数:2
C :: 3 轮数:2
C :: 4 轮数:2
C :: 5 轮数:2
A :: 1 轮数:3
A :: 2 轮数:3
B :: 1 轮数:3
B :: 2 轮数:3
B :: 3 轮数:3
C :: 1 轮数:3
C :: 2 轮数:3
C :: 3 轮数:3
C :: 4 轮数:3
C :: 5 轮数:3
A :: 1 轮数:4
A :: 2 轮数:4
B :: 1 轮数:4
B :: 2 轮数:4
B :: 3 轮数:4
C :: 1 轮数:4
C :: 2 轮数:4
C :: 3 轮数:4
C :: 4 轮数:4
C :: 5 轮数:4
A :: 1 轮数:5
A :: 2 轮数:5
B :: 1 轮数:5
B :: 2 轮数:5
B :: 3 轮数:5
C :: 1 轮数:5
C :: 2 轮数:5
C :: 3 轮数:5
C :: 4 轮数:5
C :: 5 轮数:5

Java JUC高并发编程(二)-集合&多线程锁

Java 多线程学习(一)

Java JUC高并发编程(一)相关推荐

  1. Java JUC高并发编程(三)-CallableJUC辅助类

    目录 一.Callable接口 二.JUC辅助类 1.减少计数CountDownLatch 2.循环栅栏CyclicBarrier 3.信号灯Semaphore 一.Callable接口 Callab ...

  2. 【JUC高并发编程】—— 初见JUC

    一.JUC 概述 什么是JUC JUC 是 Java并发编程的缩写,指的是 Java.util.concurrent 即Java工具集下的并发编程库 [说白了就是处理线程的工具包] JUC提供了一套并 ...

  3. java线程高并发编程

    java线程详解及高并发编程庖丁解牛 线程概述: 祖宗: 说起java高并发编程,就不得不提起一位老先生Doug Lea,这位老先生可不得了,看看百度百科对他的评价,一点也不为过: 如果IT的历史,是 ...

  4. 详解JUC高并发编程

    JUC并发编程 并发编程的本质:充分利用CPU的资源 问题:JAVA可以开启线程吗? ​ 不能:最底层是本地方法,底层是C++,Java无法直接操作硬件 1.线程里有几个状态 NEW, 新生 RUNN ...

  5. JUC高并发编程从入门到精通(全)

    目录 前言 1. Lock接口 1.1 复习synchronized 1.2 Lock接口 1.3 Lock方法 1.4 两者差异 2. 线程间通信 2.1 synchronized案例 2.2 Lo ...

  6. 高级技术之 JUC 高并发编程

    1,什么是 JUC 1.1 JUC简介 JUC 就是java.util.concurrent 工具包的简称,这一个专门用来处理线程的工具包,JDK1.5开始出现 1.2 进程与线程 **进程(Proc ...

  7. 【JUC高并发编程】—— 再见JUC

    一.读写锁 读写锁概述 1️⃣ 什么是读写锁? 读写锁是一种多线程同步机制,用于在多线程环境中保护共享资源的访问 与互斥锁不同的是,读写锁允许多个线程同时读取共享资源,但在有线程请求写操作时,必须将其 ...

  8. 《尚硅谷高级技术之JUC高并发编程》学习笔记11—— Fork / Join 框架

    文章目录 Fork / Join 框架简介 fork() 方法 join() 方法 Fork / Join 框架的异常处理 入门案例 总结 Fork / Join 框架简介 Fork / Join 它 ...

  9. JUC 高并发编程(13):LockSupport 概述, wait 与 sleep与park的区别

    LockSupport LockSupport 是一个线程阻塞工具类,所有的方法都是静态方法,可以让线程在任意位置阻塞,阻塞之后也有对应的唤醒方法.归根结底,LockSupport调用的Unsafe中 ...

最新文章

  1. 这些焊接缺陷,你遇到过多少?
  2. JavaScript——创建对象
  3. android关键应用程序,安卓开发:Android应用程序的四个关键点
  4. DP-最大递增子序列与最大递增子数组; 最大公共子序列与最大公共子数组。
  5. SQL注入如何进行攻击
  6. ospf 几种LSA类型的总结
  7. vray for 3dmax2022 中文版
  8. Maven实战从入门到精通(全)
  9. 震旦adc225打印机连接计算机,震旦ADC225打印机驱动
  10. 基于STM32战舰开发板的内部温度传感器实验
  11. 关于安装ANACONDA遇到的无法定位动态链接库问题
  12. echarts 的柱状图 填充色为透明
  13. 一周企业财报 | 阿迪达斯、盖璞、Natura、舍弗勒、百世集团等11家企业发布业绩...
  14. 既然 AAC 要比 MP3 好,且体积差不多,为什么网上不流行 AAC 格式的音频呢?
  15. 好消息!这些城市个人手机、在家“刷脸”都能提取公积金,有你家吗?
  16. 古琴销售怎么做阳php学,古琴斫琴要领
  17. 想要搭建自己的腾讯云服务器怎么做
  18. 无人驾驶汽车是如何进行行为决策的?
  19. 计算机控制在无人车中的应用,汽车无人驾驶技术的探讨
  20. 泪目!雷军突然卸任……

热门文章

  1. 2D和3D的对比,不用犹豫,3D建模是行业未来必然趋势!
  2. 北大计算机系黄铁军CCF-ADL讲习班上篇:从计算机发展史讲解制造超人工智能的正途——类脑计算...
  3. 参考文献缺少geebinf modified by zz格式解决方法
  4. Centos7安装MySQL5.7图文解析 (附MySQL安装包官网地址及MySQL5.7安装手册)
  5. 和领导谈恋爱之后,他再也不push我了,好怀念以前压榨我的时候,虽然很累,但成长很快!...
  6. 卤菜之预处理篇(辣油的制作)
  7. 导入Android项目Error:Internal error:org.gradle.tooling.BuildException: Could not execute build...
  8. CNN损失函数学习(最全)
  9. 系统中未安装任何opc服务器,OPCBrowserServer_enu.dll
  10. 以太资本:月度投资动态