Java并发——两个线程交替打印两个数组中的元素|Java并发——两个线程交替打印两个数组中的元素 | 多个线程按顺序输出数字
有两个字符数组
- number = {‘1’,‘2’,‘3’,‘4’,‘5’,‘6’,‘7’,‘8’,‘9’}
- letter = {‘A’,‘B’,‘C’,‘D’,‘E’,‘F’,‘G’,‘H’,‘I’}
- 1 A 2 B 3 C 4 D 5 E 6 F 7 G 8 H 9 I
LockSupport的方法 最简单的的一种方式,使用park和unpark的方式完成两个线程之间的通信
public static void main(String[] args) {
char[] number = {'1','2','3','4','5','6','7','8','9'};
char[] letter = {'A','B','C','D','E','F','G','H','I'};
t1 = new Thread(() ->{
for(char num : number){
System.out.print(num + " ");
LockSupport.unpark(t2);
//唤醒t2线程
LockSupport.park();
//将本线程阻塞
}
});
t2 = new Thread(() ->{
for(char let : letter){
LockSupport.park();
//防止t2线程先执行从而先输出A
System.out.print(let + " ");
LockSupport.unpark(t1);
//唤醒t1线程
}
});
t1.start();
t2.start();
}
模拟自旋锁的方式 使用一个原子类型的值当作自旋的标示,如果线程要执行时发现标示不对,则一直while自旋等待
static final AtomicInteger threadNo = new AtomicInteger(1);
public static void main(String[] args) {
char[] number = {'1','2','3','4','5','6','7','8','9'};
char[] letter = {'A','B','C','D','E','F','G','H','I'};
new Thread(() ->{
for(char num : number){
while(threadNo.get() != 1){}
System.out.print(num + " ");
threadNo.set(2);
}
}).start();
new Thread(() -> {
for(char let : letter){
while(threadNo.get() != 2){}
System.out.print(let + " ");
threadNo.set(1);
}
}).start();
}
wait/notify的方式 最经典的方式,使用wait/notify的方式完成线程通信,注意这里的synchronized不能使用this,因为这是在静态方法中,这里除了可以使用自定义的监视器,还可以使用类的Class对象。
下列写法无法正确保证是先输出1还是A,读者可自行添加CountDownLatch完成按指定顺序输出的功能。
public static void main(String[] args) {
final Object obj = new Object();
char[] number = {'1','2','3','4','5','6','7','8','9'};
char[] letter = {'A','B','C','D','E','F','G','H','I'};
new Thread(() -> {
synchronized (obj){
for(char num : number){
System.out.print(num + " ");
try {
obj.notify();
//叫醒其他线程,这里就是t2
obj.wait();
//让自己阻塞,让出锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
obj.notify();
//必须要有,因为两个线程的try里面的最后一步是阻塞,如果线程执行完了还在阻塞肯定不对,必须要唤醒,才能正确结束程序
}
}).start();
new Thread(() -> {
synchronized (obj){
for(char let : letter){
System.out.print(let + " ");
try {
obj.notify();
//叫醒其他线程,这里是t1
obj.wait();
//让自己阻塞,让出锁
} catch (InterruptedException e) {
e.printStackTrace();
}
}
obj.notify();
//同上
}
}).start();
}
ReentrantLock——单condition方式 这种方式和wait/notify方式一样,并不能体现出使用ReentrantLock可针对不同线程定制condition的优势
public static void main(String[] args) {
Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
char[] number = {'1','2','3','4','5','6','7','8','9'};
char[] letter = {'A','B','C','D','E','F','G','H','I'};
new Thread(() -> {
lock.lock();
try{
for(char num : number){
System.out.print(num + " ");
condition.signal();
condition.await();
}
condition.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally{
lock.unlock();
}
}).start();
new Thread(() -> {
lock.lock();
try{
for(char let : letter){
System.out.print(let + " ");
condition.signal();
condition.await();
}
condition.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally{
lock.unlock();
}
}).start();
}
ReentrantLock——多condition方式 使用两个condition,从而实现对不同线程的监视,体现出ReentrantLock对比wait/notify的优势特性
public static void main(String[] args) {
Lock lock = new ReentrantLock();
Condition conditionNum = lock.newCondition();
Condition conditionLet = lock.newCondition();
char[] number = {'1','2','3','4','5','6','7','8','9'};
char[] letter = {'A','B','C','D','E','F','G','H','I'};
new Thread(() -> {
lock.lock();
try{
for(char num : number){
System.out.print(num + " ");
conditionLet.signal();
conditionNum.await();
}
conditionLet.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally{
lock.unlock();
}
}).start();
new Thread(() -> {
lock.lock();
try{
for(char let : letter){
System.out.print(let + " ");
conditionNum.signal();
conditionLet.await();
}
conditionNum.signal();
} catch (InterruptedException e) {
e.printStackTrace();
} finally{
lock.unlock();
}
}).start();
}
启动三个线程,每个线程输出一个数字,要求按顺序输出1,2,3
【Java并发——两个线程交替打印两个数组中的元素|Java并发——两个线程交替打印两个数组中的元素 | 多个线程按顺序输出数字】可以采用上文中最简单的LockSupport的方式,将线程逐一唤醒执行
//思路:由于t2和t3一开始是park(阻塞)的,所以一定会先输出1,然后逐一唤醒对应线程
staticThread t11 = null, t22 = null, t33 = null;
public static void main(String[] args) {
t11 = new Thread(() -> {
System.out.println(1);
LockSupport.unpark(t22);
});
t22 = new Thread(() -> {
LockSupport.park();
System.out.println(2);
LockSupport.unpark(t33);
});
t33 = new Thread(() -> {
LockSupport.park();
System.out.println(3);
});
t11.start();
t22.start();
t33.start();
}
推荐阅读
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- 急于表达——往往欲速则不达
- 慢慢的美丽
- 《真与假的困惑》???|《真与假的困惑》??? ——致良知是一种伟大的力量
- 2019-02-13——今天谈梦想()
- 考研英语阅读终极解决方案——阅读理解如何巧拿高分
- Ⅴ爱阅读,亲子互动——打卡第178天
- 低头思故乡——只是因为睡不着
- 取名——兰
- 每日一话(49)——一位清华教授在朋友圈给大学生的9条建议