Java JUC高并发编程(一)
目录
一、概述
二、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高并发编程(一)相关推荐
- Java JUC高并发编程(三)-CallableJUC辅助类
目录 一.Callable接口 二.JUC辅助类 1.减少计数CountDownLatch 2.循环栅栏CyclicBarrier 3.信号灯Semaphore 一.Callable接口 Callab ...
- 【JUC高并发编程】—— 初见JUC
一.JUC 概述 什么是JUC JUC 是 Java并发编程的缩写,指的是 Java.util.concurrent 即Java工具集下的并发编程库 [说白了就是处理线程的工具包] JUC提供了一套并 ...
- java线程高并发编程
java线程详解及高并发编程庖丁解牛 线程概述: 祖宗: 说起java高并发编程,就不得不提起一位老先生Doug Lea,这位老先生可不得了,看看百度百科对他的评价,一点也不为过: 如果IT的历史,是 ...
- 详解JUC高并发编程
JUC并发编程 并发编程的本质:充分利用CPU的资源 问题:JAVA可以开启线程吗? 不能:最底层是本地方法,底层是C++,Java无法直接操作硬件 1.线程里有几个状态 NEW, 新生 RUNN ...
- JUC高并发编程从入门到精通(全)
目录 前言 1. Lock接口 1.1 复习synchronized 1.2 Lock接口 1.3 Lock方法 1.4 两者差异 2. 线程间通信 2.1 synchronized案例 2.2 Lo ...
- 高级技术之 JUC 高并发编程
1,什么是 JUC 1.1 JUC简介 JUC 就是java.util.concurrent 工具包的简称,这一个专门用来处理线程的工具包,JDK1.5开始出现 1.2 进程与线程 **进程(Proc ...
- 【JUC高并发编程】—— 再见JUC
一.读写锁 读写锁概述 1️⃣ 什么是读写锁? 读写锁是一种多线程同步机制,用于在多线程环境中保护共享资源的访问 与互斥锁不同的是,读写锁允许多个线程同时读取共享资源,但在有线程请求写操作时,必须将其 ...
- 《尚硅谷高级技术之JUC高并发编程》学习笔记11—— Fork / Join 框架
文章目录 Fork / Join 框架简介 fork() 方法 join() 方法 Fork / Join 框架的异常处理 入门案例 总结 Fork / Join 框架简介 Fork / Join 它 ...
- JUC 高并发编程(13):LockSupport 概述, wait 与 sleep与park的区别
LockSupport LockSupport 是一个线程阻塞工具类,所有的方法都是静态方法,可以让线程在任意位置阻塞,阻塞之后也有对应的唤醒方法.归根结底,LockSupport调用的Unsafe中 ...
最新文章
- 这些焊接缺陷,你遇到过多少?
- JavaScript——创建对象
- android关键应用程序,安卓开发:Android应用程序的四个关键点
- DP-最大递增子序列与最大递增子数组; 最大公共子序列与最大公共子数组。
- SQL注入如何进行攻击
- ospf 几种LSA类型的总结
- vray for 3dmax2022 中文版
- Maven实战从入门到精通(全)
- 震旦adc225打印机连接计算机,震旦ADC225打印机驱动
- 基于STM32战舰开发板的内部温度传感器实验
- 关于安装ANACONDA遇到的无法定位动态链接库问题
- echarts 的柱状图 填充色为透明
- 一周企业财报 | 阿迪达斯、盖璞、Natura、舍弗勒、百世集团等11家企业发布业绩...
- 既然 AAC 要比 MP3 好,且体积差不多,为什么网上不流行 AAC 格式的音频呢?
- 好消息!这些城市个人手机、在家“刷脸”都能提取公积金,有你家吗?
- 古琴销售怎么做阳php学,古琴斫琴要领
- 想要搭建自己的腾讯云服务器怎么做
- 无人驾驶汽车是如何进行行为决策的?
- 计算机控制在无人车中的应用,汽车无人驾驶技术的探讨
- 泪目!雷军突然卸任……
热门文章
- 2D和3D的对比,不用犹豫,3D建模是行业未来必然趋势!
- 北大计算机系黄铁军CCF-ADL讲习班上篇:从计算机发展史讲解制造超人工智能的正途——类脑计算...
- 参考文献缺少geebinf modified by zz格式解决方法
- Centos7安装MySQL5.7图文解析 (附MySQL安装包官网地址及MySQL5.7安装手册)
- 和领导谈恋爱之后,他再也不push我了,好怀念以前压榨我的时候,虽然很累,但成长很快!...
- 卤菜之预处理篇(辣油的制作)
- 导入Android项目Error:Internal error:org.gradle.tooling.BuildException: Could not execute build...
- CNN损失函数学习(最全)
- 系统中未安装任何opc服务器,OPCBrowserServer_enu.dll
- 以太资本:月度投资动态