本文主要是介绍回炉重造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(第二天)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!