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();
//新建一个WaitSet
static Condition condition1 = reentrantLock.newCondition();
//创建t2完成的信号变量
static Boolean t2done = false;
public static void main(String[] args) {
//创建线程t1
new 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();
//创建线程t2
new Thread(()->{
//获取锁
reentrantLock.lock();
try {
//t2直接执行
System.out.println("我t2要在前面执行!!");
//执行完后,设置信号
t2done = true;
//唤醒t1
condition1.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;
}
}