# 组成
Mark Word: 锁的信息,hashcode,垃圾回收器标志
Klass Word: 指针,包含当前对象的Class对象的地址,类对象来确定该对象是什么类型# 普通对象,占用8个字节,64位Object Header (64 bits)Mark Word(32 bits) Klass Word(32 bits)# 数组对象, 占用12个字节, 96位 包含额外的4个字节用来保存数组长度Object Header (96 bits)Mark Word(32 bits) Klass Word(32 bits) Array Length (32 bits)
- 01/00/11: 代表是否加锁
- age: 垃圾回收器标记
# 由 《操作系统》提供,又叫监视器或管程
# 操作系统可包含多个不同的Monitor
# 包含三部分1. Owner: 保存当前获取到java锁的,线程指针2. EntryList: 保存被java锁阻塞的,线程指针3. WaitSet: 保存被java锁等待的,线程指针# synchronized 的java对象,该对象会被关联到一个monitor监视器,java对象头的Mark Word就被设置为 monitor监视器的地址
- 被Synchronized修饰的java对象, 重量级锁,不公平锁
1. thread-1 通过synchronized获取到一个obj对象1.1 obj对象头信息(hashcode,age等)变为prt_to_heavyweight_monitor(30 bit)(monitor指针)1.2 obj对象头的锁状态变为 10(重量级锁)1.3 根据monitor指针,找到monitor,将Owner设置为thread-12. thread-2 过来后,检查obj锁对象头2.1 发现该obj对象头的Mark Word的锁状态已经是重量级锁2.2 根据Mark Word中锁的地址检查到当Owner已经有其他线程了2.3 thread-2进入到EntryList,进行Block3. thread-1 执行完临界区代码后,3.1 monitor的Owner进行清空3.2 将owner中的当前线程的owner和obj对象头中的monitor地址再次交换3.3 monitor唤醒EntryList中其他线程3.4 其他在 EntryList 中等待的线程, 再次竞争对象锁,再次设置monitor的Ownera. synchronized(obj),就会有一个monitor监管该对象
b. 同步代码块如果发生异常时候,也会将锁释放
c. synchronized(obj), 必须关联到同一个obj,不然就不会指向同一个monitor
# 创建锁记录
- 线程在自己的工作内存内,创建栈帧,并在活动栈帧创建一个 《锁记录》 的结构
- 锁记录: lock record address: 加锁的信息,用来保存当前线程ID等信息, 同时后续会保存对像锁的Mark WordObject Reference: 用来保存锁对象的地址00: 表示轻量级锁, 01代表无锁- 锁记录对象:是在JVM层面的,对用户无感知
- Object Body: 该锁对象的成员变量# 加锁cas-- compare and set
# cas成功
- 尝试cas交换Object中的 Mark Word和栈帧中的锁记录# cas失败
- 情况一:锁膨胀,若其他线程持有该obj对象的轻量级锁,表明有竞争,进入锁膨胀过程,加重量级锁
- 情况二:锁重入,若本线程再次synchronized锁,再添加一个Lock Record作为重入计数
- 两种情况区分: 根据obj中保存线程的lock record地址来进行判断
- null: 表示重入了几次# 解锁cas
- 退出synchronized代码块时,若为null的锁记录,表示有重入,这时清除锁记录(null清除)
- 退出synchronized代码块时,锁记录不为null,cas将Mark Word的值恢复给对象头同时obj头变为01无锁状态
- 成功则代表解锁成功; 失败说明轻量级锁进入了锁膨胀
# 加锁
- thread-0轻量级锁加锁成功
- 当thread-1进行轻量级加锁时,thread-0已经为该对象加了轻量级锁,对应的java object是00
- thread-1轻量级加锁失败,进入了锁膨胀流程# 锁膨胀
- 为Object对象申请monitor锁,并让Object的mark word 指向重量级锁地址, 同时变为10(重量级锁)
- 然后自己进入monitor的EntryList 进行 Block# 解锁
- 当Thread-0 退出同步块时,使用cas将Mark Word的值恢复给对象头,失败进入重量级解锁流程
- 按照Monitor地址找到Monitor,设置Owner为null,唤醒EntryList中BLOCKED线程
- 一个线程的重量级锁被其他线程持有时,该线程并不会直接进入阻塞
- 先本身自旋,同时查看锁资源在自旋优化期间是否能够释放 《避免阻塞时候的上下文切换》
- 若当前线程自旋成功(即此时持有锁的线程已经退出了同步块,释放了锁),这时线程就避免了阻塞
- 若自旋失败,则进入EntryList中
智能自旋:
- 自适应的: Java6之后,对象刚刚的一次自旋成功,就认为自旋成功的概率大,就会多自旋几次反之,就少自旋几次甚至不自旋
- java7之后不能控制是否开启自旋功能
- 自旋会占用cpu时间,单核自旋就是浪费,多核自旋才有意义
- Java的 JIT, 即时编译器,对热点代码进行优化
- 逃逸分析: JVM 是根据锁对象是否可以发生逃逸分析来判断
- JVM默认开启锁消除机制
- Java中锁消除默认是打开的,会根据代码中锁关联的对象是否能够逃逸决定是否优化
- 关闭锁消除: java -XX: -EliminateLocks -jar demo.jar
package com.nike.erick.d01;public class Demo07 {public static void main(String[] args) {lockMethod();nonLockMethod();}/*虽然此时加了synchronized, 但是代码在执行的时候* 1. 并不存在多线程同步访问的场景,所以synchronized 被JIT优化掉了*/private static void lockMethod() {long startTime = System.currentTimeMillis();/*做成包装类,来增加时间*/Integer number = 0;for (int i = 0; i < 10000000; i++) {synchronized (new Object()) {number++;}}System.out.println("Lock Method Times: " + (System.currentTimeMillis() - startTime));}private static void nonLockMethod() {long startTime = System.currentTimeMillis();Integer number = 0;for (int i = 0; i < 10000000; i++) {number++;}System.out.println("Non Lock Method Times: " + (System.currentTimeMillis() - startTime));}
}
private static void lockMethod() {boolean flag = true;Object lock = new Object();new Thread(() -> {synchronized (lock) {System.out.println("逃逸代码块");}}).start();long start = System.currentTimeMillis();/*** 上面锁逃逸,所以并不会进行锁消除*/for (int i = 0; i < 100000000; i++) {synchronized (lock) {flag = !flag;}}System.out.println("加锁:" + (System.currentTimeMillis() - start));}
// 互不影响的功能package com.dreamer.multithread.day04;import java.util.concurrent.TimeUnit;public class Demo02 {public static void main(String[] args) throws InterruptedException {long start = System.currentTimeMillis();BigRoom room = new BigRoom();// 睡觉的一类线程Thread firstSleep = new Thread(() -> room.sleep());Thread secondSleep = new Thread(() -> room.sleep());// 工作的一类线程Thread firstWork = new Thread(() -> room.work());Thread secondWork = new Thread(() -> room.work());firstSleep.start();secondSleep.start();firstWork.start();secondWork.start();firstSleep.join();secondSleep.join();firstWork.join();secondWork.join();// 一共需要 2*2+2*2 = 8sSystem.out.println("total time:" + (System.currentTimeMillis() - start));}
}class BigRoom {/*下面两个方法,永远不会在同一个时间调用,因此用同一把锁,浪费资源或者说不会使用同一个共享资源*/public void sleep() {synchronized (this) {try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}}}public void work() {synchronized (this) {try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}}}
}
// 执行上面的方法,只需要4s
class BigRoom {private Object sleepLock = new Object();private Object workLock = new Object();/*下面两个方法,永远不会在同一个时间调用,因此用同一把锁,浪费资源*/public void sleep() {synchronized (sleepLock) {try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}}}public void work() {synchronized (workLock) {try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}}}
}
- 线程一:持有a锁,等待b锁
- 线程二:持有b锁,等待a锁
- 互相等待引发的死锁问题
- 哲学家就餐问题
- 定位死锁: 可以借助jconsole来定位死锁
- 解决方法: 都按照相同顺序加锁就可以,但可能引发饥饿问题
package com.dreamer.multithread.day04;import java.util.concurrent.TimeUnit;public class Demo02 {public static void main(String[] args) {BigRoom room = new BigRoom();new Thread(() -> room.sleepAndWork()).start();new Thread(() -> room.workAndSleep()).start();}
}class BigRoom {private final Object sleepLock = new Object();private final Object workLock = new Object();// 互相持有对方的锁public void sleepAndWork() {synchronized (sleepLock) {consumeTime();synchronized (workLock) {System.out.println("睡醒---工作啦");}}}public void workAndSleep() {synchronized (workLock) {consumeTime();synchronized (sleepLock) {System.out.println("工作后--要睡觉啦¬");}}}private void consumeTime() {try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();}}
}
package com.dreamer.multithread.day04;public class Demo04 {private static int counter = 10;public static void main(String[] args) {new Thread(() -> {while (counter < 20) {counter++;System.out.println(" ++ 操作:" + counter);}}).start();new Thread(() -> {while (counter > 0) {counter--;System.out.println(" -- 操作:" + counter);}}).start();}
}
wait() notify() notifyAll()
Object类的方法,必须成为锁的owner时候才能使用# 当前线程进入WaitSet, 一直等待
public final void wait() throws InterruptedException# 当前线程只等待一定时间,然后从 WaitSet 重新进入EntryList来竞争锁资源
public final native void wait(long timeoutMillis) throws InterruptedException# 随便唤醒一个线程,进入到EntryList
public final native void notify()# 唤醒所有的线程,进入到EntryList
public final native void notifyAll()
1. BLOCK和WAITING的线程都处于阻塞状态,不占用cpu
2. BLOCK线程会在Owner线程释放锁时唤醒
3. WAITING线程会在Owner线程调用notify时唤醒,但唤醒后只是进入EntryList重新竞争锁
package com.nike.erick.d02;import java.util.concurrent.TimeUnit;public class Demo01 {private static Object lock = new Object();public static void main(String[] args) throws InterruptedException {Thread firstThread = new Thread(() -> {synchronized (lock) {try {System.out.println("first thread coming");/*进入WaitSet*/lock.wait();System.out.println("first thread ending....");} catch (InterruptedException e) {e.printStackTrace();}}});Thread secondThread = new Thread(() -> {synchronized (lock) {try {System.out.println("second thread coming");lock.wait();System.out.println("second thread ending....");} catch (InterruptedException e) {e.printStackTrace();}}});firstThread.start();secondThread.start();TimeUnit.SECONDS.sleep(2);/*唤醒线程必须也先获取到锁*/synchronized (lock) {/*唤醒多个线程*/lock.notifyAll();}}
}
package com.nike.erick.d02;public class Demo02 {private static Object lock = new Object();public static void main(String[] args) {new Thread(() -> {try {/*不能直接wait,要先获取到锁资源* IllegalMonitorStateException */lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}).start();}
}
1. Wait 是Object的方法 Sleep 是Thread 的静态方法
2. Wait 必须和synchronized结合使用 Sleep 不需要
3. Wait 会放弃当前线程的锁资源 Sleep 不会释放锁(如果工作时候带锁)
4. 都会让出cpu资源,状态都是Timed-Waiting
// 工作线程
synchronized(lock){while(条件不成立){lock.wait();}executeBusiness();
};//其他线程唤醒
synchronized(lock){// 实现上述条件lock.notifyAll();
}
package com.erick.multithread.d1;import java.util.concurrent.TimeUnit;public class Demo02 {private static final Object lock = new Object();private static boolean hasCigarette = false;public static void main(String[] args) throws InterruptedException {new Thread(() -> {synchronized (lock) {/*while循环: 解决虚假唤醒问题*/while (!hasCigarette) {System.out.println("烟没到,休息会儿");try {lock.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("烟来了,开始干活");}}, "t1").start();for (int i = 0; i < 5; i++) {new Thread(() -> {synchronized (lock) {System.out.println("其他人开始干活");}}).start();}TimeUnit.SECONDS.sleep(2);synchronized (lock) {hasCigarette = true;System.out.println("烟到了");lock.notify();}}
}
package com.erick.multithread.d1;import java.util.concurrent.TimeUnit;public class Demo03 {private static final Object lock = new Object();private static boolean hasCigarette = false;private static boolean hasDinner = false;public static void main(String[] args) throws InterruptedException {new Thread(() -> {synchronized (lock) {while (!hasCigarette) {System.out.println("烟没到,休息会儿");try {lock.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("烟来了,开始干活");}}, "t1").start();new Thread(() -> {synchronized (lock) {while (!hasDinner) {System.out.println("外卖没到,休息会儿");try {lock.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("外卖来了,开始干活");}}, "t2").start();for (int i = 0; i < 5; i++) {new Thread(() -> {synchronized (lock){System.out.println("其他人开始干活");}}).start();}TimeUnit.SECONDS.sleep(2);synchronized (lock) {System.out.println("烟来了");hasCigarette = true;lock.notifyAll();}}
}
- 一个结果需要从一个线程传递到另一个线程,让两个线程关联同一个GuardedObject
- JDK中, join的实现,Future的实现,就是采用Guarded Suspension
- 同步模式
package com.erick.multithread.d1;import java.util.concurrent.TimeUnit;public class Demo04 {private static GuardedResponse response = new GuardedResponse();public static void main(String[] args) {new Thread(() -> System.out.println(response.obtainResult())).start();new Thread(() -> response.populateResult()).start();}
}class GuardedResponse {private Object result;public synchronized Object obtainResult() {while (null == result) {try {System.out.println("暂未获取到资源");this.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println("已经获取到资源");return result;}public synchronized void populateResult() {result = heavyWork();this.notifyAll();}private Object heavyWork(){try {TimeUnit.SECONDS.sleep(3);return new Object();} catch (InterruptedException e) {throw new RuntimeException(e);}}
}
package com.nike.erick.d04;import java.util.ArrayList;
import java.util.concurrent.TimeUnit;public class Demo06 {private static GuardResponse guardResponse = new GuardResponse();public static void main(String[] args) {new Thread(() -> System.out.println(guardResponse.getResponse(2000))).start();new Thread(() -> {try {TimeUnit.SECONDS.sleep(1);} catch (InterruptedException e) {e.printStackTrace();}guardResponse.setResponse(new ArrayList<>());}).start();}
}class GuardResponse {private Object response;public Object getResponse(long timeoutMills) {synchronized (this) {/*开始时间*/long startTime = System.currentTimeMillis();/*经过了多长时间*/long passedTime = 0;while (response == null) {long leftTime = timeoutMills - passedTime;/*如果经过的时间大于了等待时间,则退出*/if (leftTime <= 0) {break;}/*动态等待*/try {this.wait(leftTime);} catch (InterruptedException e) {e.printStackTrace();}/*因为在wait时候可能被虚假唤醒*/passedTime = System.currentTimeMillis() - startTime;}return response;}}public void setResponse(Object response) {synchronized (this) {this.response = response;this.notify();}}
}
package com.erick.multithread.d1;import java.util.LinkedList;public class Demo05 {public static void main(String[] args) {MessageBroker messageBroker = new MessageBroker<>(5);for (int i = 0; i < 10; i++) {new Thread(() -> messageBroker.sendMessage("hello:" + Thread.currentThread().getName())).start();}for (int i = 0; i < 2; i++) {new Thread(() -> messageBroker.consumeMessage()).start();}}
}class MessageBroker {/*阻塞队列大小*/private int capacity;private LinkedList blockingQueue = new LinkedList();public MessageBroker(int capacity) {this.capacity = capacity;}public synchronized void sendMessage(T message) {while (blockingQueue.size() >= capacity) {try {System.out.println("队列已满,请稍后再发送消息");this.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}blockingQueue.addFirst(message);System.out.println("添加成功:" + Thread.currentThread().getName());this.notifyAll(); // 唤醒所有的生产者和消费者线程,不用担心虚假唤醒问题}public synchronized T consumeMessage() {while (blockingQueue.size() <= 0) {try {System.out.println("当前暂无消息,请稍后再消费");this.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}T message = blockingQueue.removeLast();this.notifyAll();return message;}
}
# 暂停当前线程
java.util.concurrent.locks.LockSupport# 在哪个线程中使用,就暂停哪个线程
public static void park()# 恢复一个线程
public static void unpark(Thread thread)
package com.dreamer.multithread.day04;import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;public class Demo01 {public static void main(String[] args) throws InterruptedException {Thread slaveThread = new Thread("slave-thread") {@Overridepublic void run() {System.out.println("prepare for PARK....");LockSupport.park();System.out.println("PARK ended");}};slaveThread.start();TimeUnit.SECONDS.sleep(2);LockSupport.unpark(slaveThread);}
}
package com.dreamer.multithread.day04;import java.util.concurrent.locks.LockSupport;public class Demo01 {public static void main(String[] args) {Thread slaveThread = new Thread("slave-thread") {@Overridepublic void run() {LockSupport.unpark(Thread.currentThread());System.out.println("prepare for PARK....");LockSupport.park();System.out.println("PARK ended");}};slaveThread.start();}
}
# 二者都会使线程进入waitset等待,都会释放锁wait/notify是Object的方法 park/unpark是LockSupport
wait/notify 必须和synchronized结合使用 park/unpark不必
wait/notify 顺序不能颠倒 park/unpark可以颠倒
wait/notify 只能随机唤醒一个或者全部唤醒 park/unpark可以指定一个线程唤醒
package com.erick.multithread.d2;import java.util.concurrent.locks.ReentrantLock;public class Demo01 {public static void main(String[] args) {FirstTest firstTest = new FirstTest();firstTest.firstMethod();}
}class FirstTest{private ReentrantLock lock = new ReentrantLock();public void firstMethod(){try {lock.lock();System.out.println("first method coming");secondMethod();}finally {/*unlock必须放在finally中,保证锁一定可以释放*/lock.unlock();}}public void secondMethod(){try{lock.lock();System.out.println("second method coming");}finally {lock.unlock();}}
}
- 没有其他线程争夺锁,则正常执行
- 有竞争时,线程就会进入EntryList,但是可以被打断
- 其他线程先获取锁,执行一段时间后,等待获取锁的线程 《打断等待》
package com.erick.multithread.d2;import java.util.concurrent.locks.ReentrantLock;public class Demo02 {private static ReentrantLock lock = new ReentrantLock();public static void main(String[] args) {new Thread(() -> {/*第一个try表示可以被打断*/try{lock.lockInterruptibly();} catch (InterruptedException e) {System.out.println("锁被打断了");throw new RuntimeException(e);}/*第二个try表示释放锁*/try{doBusiness();}finally {lock.unlock();}}).start();}private static void doBusiness(){System.out.println("do business logic");}
}
package com.erick.multithread.d2;import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;public class Demo03 {private static ReentrantLock lock = new ReentrantLock();public static void main(String[] args) {Thread firstThread = new Thread(() -> {/*获取锁的时候,可以被打断,就结束当前等待过程*/try {System.out.println("first-thread 开始等待锁");lock.lockInterruptibly();} catch (InterruptedException e) {System.out.println("first-thread 锁被打断");throw new RuntimeException(e);}try {doBusiness();} finally {lock.unlock();}});Thread secondThread = new Thread(new Runnable() {@Overridepublic void run() {try {lock.lock();/*不会释放锁*/sleep(2);firstThread.interrupt();System.out.println("second-thread完成业务");} finally {lock.unlock();}}});secondThread.start();sleep(1);firstThread.start();}private static void doBusiness() {System.out.println("do business logic");}private static void sleep(int seconds) {try {TimeUnit.SECONDS.sleep(seconds);} catch (InterruptedException e) {throw new RuntimeException(e);}}
}
# 1. 不公平锁
- 当一个线程持有锁的时候,其他线程进入锁的 EntryList
- 当线程释放锁的时候,其他线程一拥而上,而不是按照进入的顺序先到先得# 2. 公平锁: 通过ReentranLock实现
- 默认是非公平锁,传参为true,公平锁
package com.erick.multithread.d2;import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;public class Demo04 {private static ReentrantLock lock = new ReentrantLock(true);public static void main(String[] args) {new Thread(() -> {try {lock.lock();sleep(5);} finally {lock.unlock();}}).start();sleep(1);for (int i = 0; i < 3; i++) {new Thread(() -> {try {lock.lock();System.out.println(Thread.currentThread().getName() + " running");} finally {lock.unlock();}}).start();sleep(1);}}private static void sleep(int seconds) {try {TimeUnit.SECONDS.sleep(seconds);} catch (InterruptedException e) {throw new RuntimeException(e);}}
}
package com.erick.multithread.d2;import java.util.concurrent.locks.ReentrantLock;public class Demo05 {private static ReentrantLock lock = new ReentrantLock();public static void main(String[] args) {new Thread(() -> {boolean hasLock = lock.tryLock();if (!hasLock) {System.out.println("没有获取到锁,放弃");return;}try{executeBusiness();}finally {lock.unlock();}}).start();}private static void executeBusiness(){System.out.println("do business logic");}
}
package com.erick.multithread.d2;import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;public class Demo06 {private static ReentrantLock lock = new ReentrantLock();public static void main(String[] args) {new Thread(() -> {try{lock.lock();sleep(5);}finally {lock.unlock();}}).start();new Thread(() -> {boolean hasLock = lock.tryLock();if (!hasLock){System.out.println("没有获取到锁,放弃等待");return;}try{executeBusiness();}finally {lock.unlock();}}).start();}private static void executeBusiness(){System.out.println("do business logic");}private static void sleep(int seconds){try {TimeUnit.SECONDS.sleep(seconds);} catch (InterruptedException e) {throw new RuntimeException(e);}}
}
ReentrantLock public boolean tryLock(long timeout, TimeUnit unit)throws InterruptedException
package com.nike.erick.d03;import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;public class Demo06 {private static ReentrantLock reentrantLock = new ReentrantLock();public static void main(String[] args) throws InterruptedException {Thread firstThread = new Thread(() -> {reentrantLock.lock();try {TimeUnit.SECONDS.sleep(2);} catch (InterruptedException e) {e.printStackTrace();} finally {reentrantLock.unlock();}});Thread secondThread = new Thread(() -> {try {/*最长等待3s*/boolean hasLock = reentrantLock.tryLock(3, TimeUnit.SECONDS);if (!hasLock) {System.out.println("没有获取到锁");return;}try {System.out.println("Execution Business...");} finally {reentrantLock.unlock();}} catch (InterruptedException e) {System.out.println("等待锁过程中被打断了。。。");e.printStackTrace();}});firstThread.start();TimeUnit.SECONDS.sleep(1);secondThread.start();secondThread.interrupt();}
}
# 1. 创建一个等待的队列
ReentrantLock public Condition newCondition()# 2. 将一个线程在某个队列中进行等待
Condition public final void await() throws InterruptedException# 3. 去某个队列中唤醒等待的线程
Condition public final void signal()public final void signalAll()
package com.nike.erick.d03;import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;public class Demo07 {private static ReentrantLock reentrantLock = new ReentrantLock(true);private static Condition boyRoom = reentrantLock.newCondition();private static Condition girlRoom = reentrantLock.newCondition();private static boolean hasCigarette = false;private static boolean hasDinner = false;public static void main(String[] args) throws InterruptedException {/*抽烟线程*/for (int i = 0; i < 5; i++) {int boyNo = i;new Thread(() -> {reentrantLock.lock();while (true) {if (!hasCigarette) {try {System.out.println("没有烟,女孩等会-" + boyNo);boyRoom.await();// Condition的方法} catch (InterruptedException e) {e.printStackTrace();}} else {break;}try {System.out.println("男孩打仗-" + boyNo);} finally {reentrantLock.unlock();}}}).start();}for (int i = 0; i < 5; i++) {int girlNo = i;new Thread(() -> {reentrantLock.lock();while (true) {if (!hasDinner) {try {System.out.println("没有外卖,女孩等会-" + girlNo);girlRoom.await();} catch (InterruptedException e) {e.printStackTrace();}} else {break;}}try {System.out.println("女孩做鞋-" + girlNo);} finally {reentrantLock.unlock();}}).start();}TimeUnit.SECONDS.sleep(1);new Thread(() -> {reentrantLock.lock();try {hasCigarette = true;boyRoom.signalAll(); // 唤醒,让男孩线程准备获取锁资源} finally {reentrantLock.unlock();}}).start();TimeUnit.SECONDS.sleep(1);new Thread(() -> {reentrantLock.lock();try {hasDinner = true;girlRoom.signalAll(); // 唤醒,让女孩线程准备获取锁资源} finally {reentrantLock.unlock();}}).start();}
}
可重入性: Synchronized 和 ReentrantLock都支持
可打断性: Synchronized锁不能被打断 ReentrantLock可以被打断,防止死锁
超时性: Synchronized锁获取时候会一直等待 ReentrantLock支持超时等待
公平性: Synchronized的EntryList是不公平 ReentrantLock(true)公平锁
条件变量: Synchronized的WaitSet只有一个 ReentrantLock支持不同的WaitSet
package com.erick.multithread.d3;public class Demo01 {private static Object lock = new Object();public static void main(String[] args) {new Thread(() -> {synchronized (lock) {try {lock.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println("first-thread running");}}).start();new Thread(() -> {synchronized (lock) {System.out.println("second-thread running");lock.notifyAll();}}).start();}
}
package com.erick.multithread.d3;import java.sql.Time;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;public class Demo02 {private static ReentrantLock lock = new ReentrantLock();private static Condition room = lock.newCondition();public static void main(String[] args) throws InterruptedException {new Thread(() -> {try {lock.lock();room.await();System.out.println("线程一执行完毕");} catch (InterruptedException e) {throw new RuntimeException(e);} finally {lock.unlock();}}).start();TimeUnit.SECONDS.sleep(1);new Thread(() -> {try{lock.lock();System.out.println("线程二执行完毕");room.signal();}finally {lock.unlock();}}).start();}
}
package com.erick.multithread.d3;import java.util.concurrent.locks.LockSupport;public class Demo03 {public static void main(String[] args) {Thread firstThread = new Thread(() -> {LockSupport.park();System.out.println("线程一运行完毕");});firstThread.start();new Thread(() -> {System.out.println("线程二运行完毕");LockSupport.unpark(firstThread);}).start();}
}
package com.erick.multithread.d3;import java.util.Objects;public class Demo04 {private static Object lock = new Object();private static String baseChar = "a";public static void main(String[] args) {new Thread(() -> printCharacter("a", "b")).start();new Thread(() -> printCharacter("b", "c")).start();new Thread(() -> printCharacter("c", "d")).start();new Thread(() -> printCharacter("d", "e")).start();new Thread(() -> printCharacter("e", "a")).start();}private static void printCharacter(String srcChar, String targetChar) {while (true) {synchronized (lock) {while (!Objects.equals(baseChar, srcChar)) {try {lock.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}System.out.println(Thread.currentThread().getName() + ":" + baseChar);baseChar = targetChar;lock.notifyAll();}}}
}
package com.erick.multithread.d3;import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;public class Demo05 {private static String baseChar = "a";private static ReentrantLock lock = new ReentrantLock();private static Condition firstRoom = lock.newCondition();private static Condition secondRoom = lock.newCondition();private static Condition thirdRoom = lock.newCondition();private static Condition fourthRoom = lock.newCondition();private static Condition fifthRoom = lock.newCondition();public static void main(String[] args) {new Thread(() -> printCharacter("a", "b", firstRoom, secondRoom)).start();new Thread(() -> printCharacter("b", "c", secondRoom, thirdRoom)).start();new Thread(() -> printCharacter("c", "d", thirdRoom, fourthRoom)).start();new Thread(() -> printCharacter("d", "e", fourthRoom, fifthRoom)).start();new Thread(() -> printCharacter("e", "a", fifthRoom, firstRoom)).start();}private static void printCharacter(String printChar, String targetChar, Condition waitRoom, Condition signalRoom) {/*利用不同的condition,不用考虑虚假唤醒问题*/while (true) {try {lock.lock();if (baseChar != printChar) {waitRoom.await();}System.out.println(Thread.currentThread().getName() + ":" + printChar);baseChar = targetChar;signalRoom.signal();} catch (InterruptedException e) {throw new RuntimeException(e);} finally {lock.unlock();}}}
}
package com.erick.multithread.d3;import java.util.concurrent.locks.LockSupport;public class Demo06 {private static String baseChar = "a";private static Thread firstThread;private static Thread secondThread;private static Thread thirdThread;private static Thread fourthThread;private static Thread fifthThread;public static void main(String[] args) {firstThread = new Thread(() -> printCharacter("a", "b", secondThread));secondThread = new Thread(() -> printCharacter("b", "c", thirdThread));thirdThread = new Thread(() -> printCharacter("c", "d", fourthThread));fourthThread = new Thread(() -> printCharacter("d", "e", fifthThread));fifthThread = new Thread(() -> printCharacter("e", "a", firstThread));firstThread.start();secondThread.start();thirdThread.start();fourthThread.start();fifthThread.start();}private static void printCharacter(String printChar, String targetChar, Thread nextThread) {while (true){if (baseChar != printChar) {LockSupport.park();}System.out.println(Thread.currentThread().getName() + ":" + printChar);baseChar = targetChar;LockSupport.unpark(nextThread);}}
}
package com.erick.multithread.d3;public class Demo07 {private static Object lock = new Object();private static int number = 0;public static void main(String[] args) {new Thread(() -> printNum(), "t1").start();new Thread(() -> printNum(), "t2").start();}private static void printNum() {for (int i = 0; i < 10; i++) {synchronized (lock) {System.out.println(Thread.currentThread().getName() + ":" + number);number++;lock.notify();try {lock.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}}}
}
package com.erick.multithread.d3;import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;public class Demo08 {private static int number = 0;private static ReentrantLock lock = new ReentrantLock();private static Condition room = lock.newCondition();public static void main(String[] args) {new Thread(() -> printNum(), "t1").start();new Thread(() -> printNum(), "t2").start();}private static void printNum() {for (int i = 0; i < 10; i++) {try {lock.lock();System.out.println(Thread.currentThread().getName() + ":" + number);number++;room.signal();try {room.await();} catch (InterruptedException e) {throw new RuntimeException(e);}} finally {lock.unlock();}}}
}
package com.erick.multithread.d3;import java.util.concurrent.locks.LockSupport;public class Demo09 {private static int number = 0;private static Thread firstThread;private static Thread secondThread;public static void main(String[] args) {firstThread = new Thread(() -> printNum(secondThread));secondThread = new Thread(() -> printNum(firstThread));firstThread.start();secondThread.start();// 触发LockSupport.unpark(firstThread);}private static void printNum(Thread nextThread) {for (int i = 0; i < 10; i++) {LockSupport.park();System.out.println(Thread.currentThread().getName() + ":" + number);number++;LockSupport.unpark(nextThread);}}
}
上一篇:【Linux】信号