回炉重造java----JUC(第二天)

2024-06-06 02:04
文章标签 java 第二天 juc 回炉 重造

本文主要是介绍回炉重造java----JUC(第二天),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Monitor---监视器/管程

对象头:

操作系统提供的Monitor对象

Synchronized底层实现原理:

①锁对象在加了synchronized之后,对象头中的Mark Word中就存了一个Monitor的地址指针。

②当一个线程获取到锁之后,Monitor中的Owner属性指向了该获得锁的线程。

③当锁还没释放时,其他的线程来获得锁,就会进入EntryList等待队列中等待。

④当线程2释放锁之后,通知Monitor中的等待队列中的线程,通过一些策略进行选择一个线程拿出来并且获得锁,把Owner指向该获得锁的线程。

⑤当一个线程获取到锁后,发现自身任不满足一些条件,就会调用wait()方法进入Wait_Set中等待(此时线程是进入了Waiting状态),当另一个线程获得锁并且把条件送过来了(即调用notify()唤醒Wait_Set方法中的一个线程或者使用notifyAll()唤醒所有的线程),然后线程就可以再次进入EntryList中去竞争获得锁。

字节码指令:

Synchronized优化/升级

线程状态的转换

1:start():NEW----->Runnable

2:wait():Runnable------> Waiting。notify(),notifyAll(),interrupt():Waiting------>Runnable(注意这里从Waiting转向Runnable是竞争获取到了锁,如果没获取到锁,则会进入Blocked)。

3:join():Runnable------> Waiting。子线程结束或者interrupt():Waiting------>Runnable。

4:park():Runnable------> Waiting。unpark():Waiting------>Runnable。

5:wait(time):Runnable------> Timed_Waiting。超过时间或者被唤醒:Timed_Waiting------>Runnable(注意这里从Timed_Waiting转向Runnable也是竞争获取到了锁,如果没获取到锁,则会进入Blocked)。

6,8:join(time)/parkNanos(time):Runnable------> Timed_Waiting。超过时间或者被唤醒:Timed_Waiting------>Runnable

7:sleep(time):Runnable------> Timed_Waiting。时间到了或者被唤醒:Timed_Waiting------>Runnable。

9:获取锁失败:Runnable------>Blocked。获取锁成功:Runnable------>Blocked。

10:执行代码结束:Runnable------>Terminated。

活锁与死锁

活锁:是一种现象,两个线程一直改变对方的结束条件,导致两个线程都无法结束,一直僵持运行下去。

死锁:死锁是两个线程为了获得锁,并且都需要对象已经占有的锁,导致谁也无法获取的锁,一直僵持死锁状态。

ReentrantLock(可重入锁) 

主要特点:①可中断(其他线程可以通过interrupt()打断正在等待锁的线程)

                  ②可设置超时时间(一个线程尝试获得锁失败后,一般会进行阻塞状态一直等待锁,但是ReentrantLock可设置一个超时时间,当等待时间超过该时间就会自动放弃获得锁)

                  ③可设置为公平锁(先来的线程先获得锁,解决饥饿问题,但是会降低并发度)

                  ④支持多个条件变量(支持多个WaitSet去存放等待的线程,通过Condition中的await()方法去让想线程放进等待室,通过signal()或者signalAll()去唤醒对应休息室的线程)

                  ⑤与Synchronized一样,都支持可重入(可重入就是当一个线程获得了锁之后,如果再次尝试获得该锁也会成功,如果是非重入的话,第二次获得就会把自己锁住)

public class ReentrantLockTest {private static ReentrantLock lock = new ReentrantLock();public static void main(String[] args) {lock.lock();try {System.out.println("我获得了锁,开始操作");m1();}finally {lock.unlock();System.out.println("我释放锁了");}}public static void m1(){lock.lock();try {System.out.println("我重入了锁,要开始我自己的操作");}finally {lock.unlock();System.out.println("我释放锁了");}}
}

同步模式---顺序执行线程

 wait()和notify()方式:

public class SortThreadTest {static final Object lock = new Object(); //锁对象static boolean t2done = false; //t2是否执行的信号public static void main(String[] args) {//创建t1线程new Thread(()->{//获得锁synchronized (lock){while (! t2done){ //判断t2是否已经执行完try {lock.wait(); //如果没有执行,则让出CPU去等待} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("我t1成功执行!!!"); //如果t2已经执行,t1再执行}}).start();//创建t2线程new Thread(()->{//获得锁synchronized (lock){System.out.println("我t2要先执行呀!!!"); //t2要先执行,就直接执行t2done = true; //改变信号lock.notify(); //去WaitSet中唤醒正在等待的t1}}).start();}
}

await()和signal()方式:

public class SortThreadTest01 {//创建ReentrantLock对象private static ReentrantLock reentrantLock = new ReentrantLock();//新建一个WaitSetstatic Condition condition1 = reentrantLock.newCondition();//创建t2完成的信号变量static Boolean t2done = false;public static void main(String[] args) {//创建线程t1new Thread(()->{//获取锁reentrantLock.lock();try {while (! t2done){//t2还没执行,进入WaitSet等待try {condition1.await();} catch (InterruptedException e) {e.printStackTrace();}}//t2执行完毕后,t1执行System.out.println("我t1要在后面执行!!");}finally {//释放锁reentrantLock.unlock();}}).start();//创建线程t2new Thread(()->{//获取锁reentrantLock.lock();try {//t2直接执行System.out.println("我t2要在前面执行!!");//执行完后,设置信号t2done = true;//唤醒t1condition1.signal();}finally {//释放锁reentrantLock.unlock();}}).start();}
}

同步模式---交替执行线程

public class CrossThreadTest {public static void main(String[] args) {test t = new test(1,5);new Thread(()->{t.print("a",1,2);}).start();new Thread(()->{t.print("b",2,3);}).start();new Thread(()->{t.print("c",3,1);}).start();}}class test{public void print(String str,int waitflag,int nextflag){for (int i = 0; i < loopnumber; i++) {synchronized (this){while (flag != waitflag){try {this.wait();}catch (InterruptedException e){e.printStackTrace();}}System.out.print(str);flag = nextflag;this.notifyAll();}}}private int flag;private int loopnumber;public test(int flag, int loopnumber) {this.flag = flag;this.loopnumber = loopnumber;}
}

这篇关于回炉重造java----JUC(第二天)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1034790

相关文章

JAVA SE包装类和泛型详细介绍及说明方法

《JAVASE包装类和泛型详细介绍及说明方法》:本文主要介绍JAVASE包装类和泛型的相关资料,包括基本数据类型与包装类的对应关系,以及装箱和拆箱的概念,并重点讲解了自动装箱和自动拆箱的机制,文... 目录1. 包装类1.1 基本数据类型和对应的包装类1.2 装箱和拆箱1.3 自动装箱和自动拆箱2. 泛型2

SpringBoot操作MaxComputer方式(保姆级教程)

《SpringBoot操作MaxComputer方式(保姆级教程)》:本文主要介绍SpringBoot操作MaxComputer方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的... 目录引言uqNqjoe一、引入依赖二、配置文件 application.properties(信息用自己

JavaScript中的Map用法完全指南

《JavaScript中的Map用法完全指南》:本文主要介绍JavaScript中Map用法的相关资料,通过实例讲解了Map的创建、常用方法和迭代方式,还探讨了Map与对象的区别,并通过一个例子展... 目录引言1. 创建 Map2. Map 和对象的对比3. Map 的常用方法3.1 set(key, v

Javascript访问Promise对象返回值的操作方法

《Javascript访问Promise对象返回值的操作方法》这篇文章介绍了如何在JavaScript中使用Promise对象来处理异步操作,通过使用fetch()方法和Promise对象,我们可以从... 目录在Javascript中,什么是Promise1- then() 链式操作2- 在之后的代码中使

JAVA虚拟机中 -D, -X, -XX ,-server参数使用

《JAVA虚拟机中-D,-X,-XX,-server参数使用》本文主要介绍了JAVA虚拟机中-D,-X,-XX,-server参数使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有... 目录一、-D参数二、-X参数三、-XX参数总结:在Java开发过程中,对Java虚拟机(JVM)的启动参数进

Java中数组转换为列表的两种实现方式(超简单)

《Java中数组转换为列表的两种实现方式(超简单)》本文介绍了在Java中将数组转换为列表的两种常见方法使用Arrays.asList和Java8的StreamAPI,Arrays.asList方法简... 目录1. 使用Java Collections框架(Arrays.asList)1.1 示例代码1.

Java中使用注解校验手机号格式的详细指南

《Java中使用注解校验手机号格式的详细指南》在现代的Web应用开发中,数据校验是一个非常重要的环节,本文将详细介绍如何在Java中使用注解对手机号格式进行校验,感兴趣的小伙伴可以了解下... 目录1. 引言2. 数据校验的重要性3. Java中的数据校验框架4. 使用注解校验手机号格式4.1 @NotBl

SpringBoot自定义注解如何解决公共字段填充问题

《SpringBoot自定义注解如何解决公共字段填充问题》本文介绍了在系统开发中,如何使用AOP切面编程实现公共字段自动填充的功能,从而简化代码,通过自定义注解和切面类,可以统一处理创建时间和修改时间... 目录1.1 问题分析1.2 实现思路1.3 代码开发1.3.1 步骤一1.3.2 步骤二1.3.3

SpringBoot基于沙箱环境实现支付宝支付教程

《SpringBoot基于沙箱环境实现支付宝支付教程》本文介绍了如何使用支付宝沙箱环境进行开发测试,包括沙箱环境的介绍、准备步骤、在SpringBoot项目中结合支付宝沙箱进行支付接口的实现与测试... 目录一、支付宝沙箱环境介绍二、沙箱环境准备2.1 注册入驻支付宝开放平台2.2 配置沙箱环境2.3 沙箱

使用Java发送邮件到QQ邮箱的完整指南

《使用Java发送邮件到QQ邮箱的完整指南》在现代软件开发中,邮件发送功能是一个常见的需求,无论是用户注册验证、密码重置,还是系统通知,邮件都是一种重要的通信方式,本文将详细介绍如何使用Java编写程... 目录引言1. 准备工作1.1 获取QQ邮箱的SMTP授权码1.2 添加JavaMail依赖2. 实现