目录
- 背景介绍
- 实现方式
- 总结提升
背景介绍
有一个需求是要求多个线程去执行任务,需要每个线程都执行一次之后再继续执行,也就是说每个线程交替去执行任务。举个例子来说,有两个线程,一个输出字母,一个输出数字。交替输出1A2B3C4D5E…来实现这样一个业务场景。
实现方式
- 使用LockSupport类中的unpark方法和park方法。unpark方法用来叫醒指定的线程,park方法用来将当前队列进入到阻塞的状态。
package com.example.threadpool.LockSupport;
import java.util.concurrent.locks.LockSupport;
/**
* @BelongsProject: demo
* @BelongsPackage: com.example.threadpool.LockSupport
* @Author: Wuzilong
* @Description: 使用LockSupport类中的park和unpark方法实现线程交替执行
* @CreateTime: 2023-11-11 10:07
* @Version: 1.0
*/
public class AlternatingExecution {
private static Thread t1;
private static Thread t2;
public static void main(String[] args) {
char[] oneArray="1234567".toCharArray();
char[] twoArray="ABCDEFG".toCharArray();
t1=new Thread(() ->{
for (char one : oneArray){
System.out.print(one);
LockSupport.unpark(t2);//叫醒t2线程
LockSupport.park();//阻塞当前线程
}
},"t1");
t2 = new Thread(() ->{
for (char two: twoArray){
LockSupport.park();
System.out.print(two);
LockSupport.unpark(t1);
}
},"t2");
t1.start();
t2.start();
}
}
运行结果
- 使用synchronized锁和notify方法和wait方法实现线程交替执行,notify方法事用来唤醒线程,wait方法是将当前的线程放到等待队列中等待执行,不允许执行其他的动作。
package com.example.threadpool.sync_notify_wait;
/**
* @BelongsProject: demo
* @BelongsPackage: com.example.threadpool.sync_notify_wait
* @Author: Wuzilong
* @Description: 使用synchronized锁住o对象,然后使用notify唤醒线程和wait去让线程等待
* @CreateTime: 2023-11-11 14:25
* @Version: 1.0
*/
public class Client {
public static void main(String[] args) {
Object o = new Object();
char[] oneArray="123456".toCharArray();
char[] twoArray="ABCDEF".toCharArray();
new Thread(()->{
synchronized (o){
for (char one:oneArray){
System.out.print(one);
try{
o.notify();//唤醒线程
o.wait();//将线程放到等待队列中等待执行,不允许执行其他的动作
}catch ( Exception e){
e.printStackTrace();
}
}
o.notify();//必须添加,否则无法停止程序
}
},"t1").start();
new Thread(()->{
synchronized (o){
for(char two:twoArray){
System.out.print(two);
try{
o.notify();
o.wait();
}catch (Exception e){
e.printStackTrace();
}
}
o.notify();
}
},"t2").start();
}
}
运行结果
- 使用Lock锁和condition的signal方法和await方法实现多线程之间交替执行,signal方法用来唤醒其他线程,await方法用来将当前线程进入阻塞队列。
package com.example.threadpool.lock_condition;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @BelongsProject: demo
* @BelongsPackage: com.example.threadpool.lock_condition
* @Author: Wuzilong
* @Description: 描述什么人干什么事儿
* @CreateTime: 2023-11-11 15:39
* @Version: 1.0
*/
public class Client {
public static void main(String[] args) {
char oneArray[]="123456".toCharArray();
char twoArray[]="ABCDEF".toCharArray();
Lock lock=new ReentrantLock();
Condition condition = lock.newCondition();
new Thread(()->{
lock.lock();
try{
for (char one: oneArray){
System.out.println(one);
condition.signal(); //唤醒其他线程
condition.await(); //当前线程进入阻塞队列
}
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
},"t1").start();
new Thread(()->{
lock.lock();
try{
for (char two:twoArray){
System.out.println(two);
condition.signal();
condition.await();
}
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
},"t2").start();
}
}
运行结果
- 使用LinkedTransferQueue队列中的take方法和transfer方法实现多个线程交替执行,transfer方法是向队列中添加内容,添加的内容如果没有被使用是不会执行下面的代码逻辑的,take方法是从队列中获取内容。
package com.example.threadpool.TransferQueue;
import java.util.concurrent.LinkedTransferQueue;
import java.util.concurrent.TransferQueue;
/**
* @BelongsProject: demo
* @BelongsPackage: com.example.threadpool.TransferQueue
* @Author: Wuzilong
* @Description: 描述什么人干什么事儿
* @CreateTime: 2023-11-11 16:39
* @Version: 1.0
*/
public class Client {
public static void main(String[] args) {
char[] oneArray="123456".toCharArray();
char[] twoArray="ABCDEF".toCharArray();
//声明一个队列
TransferQueue<Character> queue=new LinkedTransferQueue<>();
new Thread(()->{
try{
for (char one:oneArray){
System.out.print(queue.take()); //从队列中获取内容
queue.transfer(one);
}
}catch (Exception e){
e.printStackTrace();
}
},"t1").start();
new Thread(()->{
try{
for(char two :twoArray){
queue.transfer(two); //向队列中添加内容,添加的内容如果没有被拿走是不会执行下面的代码逻辑的。
System.out.print(queue.take());
}
}catch (Exception e){
e.printStackTrace();
}
},"t2").start();
}
}
运行效果
总结提升
对于一个需求的实现方式有很多种,我们可以通过不同的维度,针对于业务的侧重点不同来由不同的实现方式,我们要有无限的思想去思考问题,要有发展的眼光去看待问题。