结论
synchronized
synchronized 配合 wait()/notify 无法实现精准唤醒线程
ReentrantLock
ReentrantLock 配合 Condition await()/signal() 可以实现精准唤醒线程 (指唤醒指定的线程)
ReentrantLock 如何实现精准唤醒线程
一个 lock 配合多个 Condition, 且每个 Condition 中只有一个线程
(若一个Condition中有多个线程,也无法精准唤醒线程)
案例 synchronized
public class ManySync {
public void await1() {
synchronized (this) {
try {
System.out.println("await1 - 进入等待" + Thread.currentThread().getName());
this.wait();
System.out.println("await1 - 被唤醒" + Thread.currentThread().getName());
} catch (Exception e) {
e.printStackTrace();
}
}
}
public synchronized void await2() {
synchronized (this) {
try {
System.out.println("await2 - 进入等待" + Thread.currentThread().getName());
this.wait();
System.out.println("await2 - 被唤醒" + Thread.currentThread().getName());
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void await3() {
synchronized (this) {
try {
System.out.println("await3 - 进入等待" + Thread.currentThread().getName());
this.wait();
System.out.println("await3 - 被唤醒" + Thread.currentThread().getName());
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void await4() {
synchronized (this) {
try {
System.out.println("await4 - 进入等待" + Thread.currentThread().getName());
this.wait();
System.out.println("await4 - 被唤醒" + Thread.currentThread().getName());
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void notif() {
synchronized(this) {
try {
this.notify();
this.notify();
this.notify();
this.notify();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
class Run3 {
public static void main(String[] args) {
try {
ManySync manySync = new ManySync();
Thread t1 = new Thread(() -> {
manySync.await1();
});
Thread t2 = new Thread(() -> {
manySync.await2();
});
Thread t3 = new Thread(() -> {
manySync.await3();
});
Thread t4 = new Thread(() -> {
manySync.await4();
});
t1.start();
Thread.sleep(200);
t2.start();
Thread.sleep(200);
t3.start();
Thread.sleep(200);
t4.start();
Thread.sleep(1000);
manySync.notif();
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出结果 可以看出等待时间长的锁并不会最先被唤醒, 也无法唤醒指定线程,(因为并未提供能唤醒的API,也无法进行设计) 唤醒的输出结果是随机的 由 JVM 调度
await1 - 进入等待Thread-0
await2 - 进入等待Thread-1
await3 - 进入等待Thread-2
await4 - 进入等待Thread-3
await1 - 被唤醒Thread-0
await4 - 被唤醒Thread-3
await3 - 被唤醒Thread-2
await2 - 被唤醒Thread-1
案例 ReentrantLock
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ManyCondition {
private Lock lock = new ReentrantLock();
Condition condition1 = lock.newCondition();
Condition condition2 = lock.newCondition();
Condition condition3 = lock.newCondition();
Condition condition4 = lock.newCondition();
public void await1() {
try {
lock.lock();
System.out.println("await1 - 进入等待" + Thread.currentThread().getName());
condition1.await();
System.out.println("await1 - 被唤醒" + Thread.currentThread().getName());
lock.unlock();
} catch (Exception e) {
e.printStackTrace();
}
}
public void await2() {
try {
lock.lock();
System.out.println("await2 - 进入等待" + Thread.currentThread().getName());
condition2.await();
System.out.println("await2 - 被唤醒" + Thread.currentThread().getName());
lock.unlock();
} catch (Exception e) {
e.printStackTrace();
}
}
public void await3() {
try {
lock.lock();
System.out.println("await3 - 进入等待" + Thread.currentThread().getName());
condition3.await();
System.out.println("await3 - 被唤醒" + Thread.currentThread().getName());
lock.unlock();
} catch (Exception e) {
e.printStackTrace();
}
}
public void await4() {
try {
lock.lock();
System.out.println("await4 - 进入等待" + Thread.currentThread().getName());
condition4.await();
System.out.println("await4 - 被唤醒" + Thread.currentThread().getName());
lock.unlock();
} catch (Exception e) {
e.printStackTrace();
}
}
public void signal() {
try {
lock.lock();
System.out.println("await1 - 被唤醒 - " + Thread.currentThread().getName());
condition1.signal();
lock.unlock();
lock.lock();
System.out.println("await2 - 被唤醒 - " + Thread.currentThread().getName());
condition2.signal();
lock.unlock();
lock.lock();
System.out.println("await3 - 被唤醒 - " + Thread.currentThread().getName());
condition3.signal();
lock.unlock();
lock.lock();
System.out.println("await4 - 被唤醒 - " + Thread.currentThread().getName());
condition4.signal();
lock.unlock();
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Run2 {
public static void main(String[] args) {
try {
ManyCondition manyCondition = new ManyCondition();
Thread t1 = new Thread(() -> {
manyCondition.await1();
});
Thread t2 = new Thread(() -> {
manyCondition.await2();
});
Thread t3 = new Thread(() -> {
manyCondition.await3();
});
Thread t4 = new Thread(() -> {
manyCondition.await4();
});
t1.start();
t2.start();
t3.start();
t4.start();
Thread.sleep(2000);
manyCondition.signal();
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出结果 这里可以看出 ,当每个Condition 中只有一个线程时, 可以通过逻辑控制, 实现精准唤醒需要唤醒的线程
await1 - 进入等待Thread-0
await2 - 进入等待Thread-1
await3 - 进入等待Thread-2
await4 - 进入等待Thread-3
await1 - 被唤醒 - main
await2 - 被唤醒 - main
await3 - 被唤醒 - main
await4 - 被唤醒 - main
await1 - 被唤醒Thread-0
await2 - 被唤醒Thread-1
await3 - 被唤醒Thread-2
await4 - 被唤醒Thread-3