Concurrency Programming 六
同步模式之顺序控制
1. 固定运行顺序
1.1 wait& notify版
public class App {
private static Object obj = new Object();
private static boolean flag = false;
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
synchronized (obj) {
while (!flag) {
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println(Thread.currentThread().getName());
}, "t1");
Thread t2 = new Thread(() -> {
System.out.println(Thread.currentThread().getName());
synchronized (obj) {
flag = true;
obj.notifyAll(); // 通知等待线程(可能有多个, 因此需要用 notifyAll)
}
}, "t2");
t1.start();
t2.start();
}
}
1.2 park& unpark版
- 不同于 wait& notify的 notify, 解锁(unpark)可以先被执行
public class App {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
LockSupport.park();
System.out.println(Thread.currentThread().getName());
}, "t1");
Thread t2 = new Thread(() -> {
System.out.println(Thread.currentThread().getName());
// 给 t1线程, 发放一个许可(多次连续调用 unpark(), 依然只会发放一个许可)
LockSupport.unpark(t1);
}, "t2");
t1.start();
t2.start();
}
}
2. 交替输出
2.1 wait& notify版
- 线程1输出 a 3次, 线程2输出 b 3次, 线程3输出 c 3次
class Alternately {
private int flag;
private int loopNumber;
// @param int flag: 开始标记
// @param int loopNumber: 轮询输出次数
public Alternately(int flag, int loopNumber) {
this.flag = flag;
this.loopNumber = loopNumber;
}
public void print(int waitFlag, int nextFlag, String str) {
for (int i = 0; i < loopNumber; i++) {
synchronized (this) {
// 不同时, 进入阻塞队列
while (this.flag != waitFlag) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 标记相同, 则输出
System.out.print(str);
// 将标记改为下一个指定的标记
flag = nextFlag;
// 唤醒所有当前阻塞中的线程
this.notifyAll();
}
}
}
}
public class App {
public static void main(String[] args) {
Alternately alternately = new Alternately(1, 3);
new Thread(() -> {
alternately.print(1, 2, "a");
}).start();
new Thread(() -> {
alternately.print(2, 3, "b");
}).start();
new Thread(() -> {
alternately.print(3, 1, "c-");
}).start();
}
}
abc-abc-abc-
2.2 ReentrantLock条件变量版
class AwaitSignal extends ReentrantLock {
private int loopNumber;
public AwaitSignal(int loopNumber) {
this.loopNumber = loopNumber;
}
public void start(Condition first) {
this.lock();
try {
System.out.println("start!");
first.signal();
} finally {
this.unlock();
}
}
public void print(String str, Condition current, Condition next) {
for (int i = 0; i < loopNumber; i++) {
this.lock();
try {
current.await();
System.out.print(str);
next.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
this.unlock();
}
}
}
}
public class App {
public static void main(String[] args) {
AwaitSignal as = new AwaitSignal(5);
Condition aWaitSet = as.newCondition();
Condition bWaitSet = as.newCondition();
Condition cWaitSet = as.newCondition();
new Thread(() -> as.print("a", aWaitSet, bWaitSet)).start();
new Thread(() -> as.print("b", bWaitSet, cWaitSet)).start();
new Thread(() -> as.print("c-", cWaitSet, aWaitSet)).start();
as.start(aWaitSet);
}
}
start!
abc-abc-abc-abc-abc-
2.3 park& unpark版
class Alternately {
private int loopNumber;
private Thread[] threads;
public Alternately(int loopNumber) {
this.loopNumber = loopNumber;
}
public void setThreads(Thread... threads) {
this.threads = threads;
}
public void print(String str) {
for (int i = 0; i < loopNumber; i++) {
LockSupport.park();
System.out.print(str);
LockSupport.unpark(nextThread());
}
}
private Thread nextThread() {
Thread current = Thread.currentThread();
int index = 0;
for (int i = 0; i < threads.length; i++) {
if(threads[i] == current) {
index = i;
break;
}
}
// 如果当前线程为 t1或 t2, 则通过
if(index < threads.length - 1) {
// 返回当前线程的下一个线程
return threads[index + 1];
} else {
return threads[0];
}
}
public void start() {
// 轮询开启各个线程
for (Thread thread : threads) {
thread.start();
}
// 给第一个线程, 发放一个许可(唤醒)
LockSupport.unpark(threads[0]);
}
}
public class App {
public static void main(String[] args) {
Alternately alternately = new Alternately(5);
Thread t1 = new Thread(() -> alternately.print("a"));
Thread t2 = new Thread(() -> alternately.print("b"));
Thread t3 = new Thread(() -> alternately.print("c-"));
alternately.setThreads(t1, t2, t3);
alternately.start();
}
}
abc-abc-abc-abc-abc-
如果您觉得有帮助,欢迎点赞哦 ~ 谢谢!!