并发学习记录08:控制线程运行次序
假如有一个需求,要多线程输出2,然后再输出1,就是要控制多线程输出的顺序,试着去实现
方法1:wait,notify
@Slf4j(topic = "ch.XianChengTongBuTest01")
public class XianChengTongBuTest01 {
static final Object lock = new Object();
static boolean t2Run = false;
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
synchronized (lock) {
while (!t2Run) {
log.debug("t2没运行完,再等等");
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
log.debug("2");
}
}, "t1");
Thread t2 = new Thread(() -> {
synchronized (lock) {
log.debug("1");
lock.notify();
t2Run = true;
}
}, "t2");
t1.start();
t2.start();
}
}
方法2:用park和unpark
@Slf4j(topic = "ch.XianChengTongBuTest02")
public class XianChengTongBuTest02 {
static boolean t2Run = false;
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
log.debug("t2没运行,t1等着");
LockSupport.park();
log.debug("1");
}, "t1");
Thread t2 = new Thread(() -> {
log.debug("2");
LockSupport.unpark(t1);
}, "t2");
t1.start();
t2.start();
}
}
方法3:用ReentrantLock
@Slf4j(topic = "ch.XianChengTongBuTest03")
public class XianChengTongBuTest03 {
static ReentrantLock lock = new ReentrantLock();
static boolean t2Run = false;
static Condition t2Ready = lock.newCondition();
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
lock.lock();
while (!t2Run) {
log.debug("t2还没好");
try {
t2Ready.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
lock.unlock();
log.debug("1");
}, "t1");
Thread t2 = new Thread(() -> {
log.debug("2");
t2Run = true;
lock.lock();
t2Ready.signal();
lock.unlock();
}, "t2");
t1.start();
t2.start();
}
}
假如有另外一个需求,是要有三个线程分别打印abc,三个线程循环打印abc五次,最后会有一个结果abcabcabcabcabc,试着去实现
实现1:利用wait-notifyAll去实现
public class TongBuTest01 {
public static void main(String[] args) {
WaitNotify wn = new WaitNotify(1, 5);
new Thread(() -> {
wn.print("a", 1, 2);
}, "1").start();
new Thread(() -> {
wn.print("b", 2, 3);
}, "2").start();
new Thread(() -> {
wn.print("c", 3, 1);
}, "3").start();
}
}
class WaitNotify {
private int flag;
private int loopNumber;
public WaitNotify(int flag, int loopNumber) {
this.flag = flag;
this.loopNumber = loopNumber;
}
/**
* @param str 打印字符串
* @param waitFlag 关于本次输出的标记
* @param nextFlag 关于下次输出的标记
*/
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();
}
}
}
}
实现2:利用ReentrantLock去实现
//使用ReentrantLock解决
public class TongBuTest02 {
public static void main(String[] args) throws InterruptedException {
MyReentrantLock lock = new MyReentrantLock(5);
Condition c1 = lock.newCondition();
Condition c2 = lock.newCondition();
Condition c3 = lock.newCondition();
Thread t1 = new Thread(() -> {
lock.print("a", c1, c2);
}, "1");
Thread t2 = new Thread(() -> {
lock.print("b", c2, c3);
}, "2");
Thread t3 = new Thread(() -> {
lock.print("c", c3, c1);
}, "3");
t1.start();
t2.start();
t3.start();
Thread.sleep(1000);
lock.lock();
try {
c1.signal();
} finally {
lock.unlock();
}
}
}
class MyReentrantLock extends ReentrantLock {
private int loopNumber;
public MyReentrantLock(int loopNumber) {
this.loopNumber = loopNumber;
}
public void print(String str, Condition current, Condition next) {
for (int i = 0; i < loopNumber; i++) {
lock();
try {
current.await();
System.out.print(str);
next.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
unlock();
}
}
}
}
实现3:利用parkUnpark去实现:
//利用park和unpark解决同步问题
public class TongBuTest03 {
static Thread t1;
static Thread t2;
static Thread t3;
public static void main(String[] args) throws InterruptedException {
ParkUnpark parkUnpark = new ParkUnpark(5);
t1 = new Thread(() -> {
parkUnpark.print("a",t2);
}, "t1");
t2 = new Thread(() -> {
parkUnpark.print("b",t3);
}, "t1");
t3 = new Thread(() -> {
parkUnpark.print("c",t1);
}, "t1");
t1.start();
t2.start();
t3.start();
Thread.sleep(1000);
LockSupport.unpark(t1);
}
}
class ParkUnpark {
private int loopNumber;
public ParkUnpark(int loopNumber) {
this.loopNumber = loopNumber;
}
public void print(String str, Thread next) {
for (int i = 0; i < loopNumber; i++) {
LockSupport.park();
System.out.print(str);
LockSupport.unpark(next);
}
}
}
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现