解决线程顺序有几种方式
其实,这个问题比较简单.主要考察对 join方法的掌握。
来了解下join
thread.join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。
如:在线程B中调用了线程A的join方法,只有A执行完毕,才会继续执行线程B。
t.join(); //调用join方法,等待线程执行完毕
t.join(1000); //等待t线程,等待时间是1000毫秒。
join的原理
任何地方当调用了t.join(),就必须要等待线程t执行完毕后,才能继续执行其他线程。这里其实是运用了Java中最顶级对象Object提供的方法wait()。wait()方法用于线程间通信,它的含义是通知一个线程等待一下,让出CPU资源,注意这里是会放弃已经占有的资源的。直到t线程执行完毕,再调用notify()唤醒当前正在运行的线程。
一般来说,可以用三种方式:
1. 使用join
例子,具体代码:
先准备3个线程,然后在线程中,调动另一个线程的join方法。
public class JoinDemo { //main方法测试 public static void main(String[] args) { //线程1 final Thread t1 = new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " run 1"); } }, "T1"); //线程2 final Thread t2 = new Thread(new Runnable() { @Override public void run() { try { //t1想插队,t1执行完,t2才能执行 t1.join(); System.out.println(Thread.currentThread().getName() + " run 2"); } catch (InterruptedException e) { e.printStackTrace(); } } }, "T2"); //线程3 final Thread t3 = new Thread(new Runnable() { @Override public void run() { try { //t2想插队,t2执行完,t3才能执行 t2.join(); System.out.println(Thread.currentThread().getName() + " run 3"); } catch (InterruptedException e) { e.printStackTrace(); } } }, "T3"); t1.start(); t2.start(); t3.start(); System.out.println("-----------------------"); } }
执行结果:
看结果的确是,按照顺序执行。
2:单个线程池newSingleThreadExecutor
上面的案例改造下:
public class Join2Demo { public static void main(String[] args) { final Thread t1 = new Thread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " run 1"); } }, "T1"); final Thread t2 = new Thread(new Runnable() { @Override public void run() { try { t1.join(); System.out.println(Thread.currentThread().getName() + " run 2"); } catch (InterruptedException e) { e.printStackTrace(); } } }, "T2"); final Thread t3 = new Thread(new Runnable() { @Override public void run() { try { t2.join(); System.out.println(Thread.currentThread().getName() + " run 3"); } catch (InterruptedException e) { e.printStackTrace(); } } }, "T3"); // // 线程池写法2 // ExecutorService executor = Executors.newSingleThreadExecutor(); // executor.submit(t1); // executor.submit(t2); // executor.submit(t3); // executor.shutdown(); //线程池写法2 (阿里推荐写法) 手动创建线程池,让开发者了解线程的基本信息,便于控制 ExecutorService pool = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(2), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy()); pool.execute(t1); pool.execute(t2); pool.execute(t3); pool.shutdown();//gracefully shutdown } }
运行结果:
结果和预期一样。
3: 锁+共享变量
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class OrderDemo { private static Lock lock = new ReentrantLock(); private static int state = 0; //线程1 static class ThreadA extends Thread{ @Override public void run(){ for (int i = 0; i < 10; ) { lock.lock(); try { if (state % 3 == 0){ System.out.println(Thread.currentThread().getName() + "A"); state++; i++; } }finally { lock.unlock(); } } } } //线程2 static class ThreadB extends Thread{ @Override public void run(){ for (int i = 0; i < 10; ) { lock.lock(); try { if (state % 3 == 1){ System.out.println(Thread.currentThread().getName() + "B"); state++; i++; } }finally { lock.unlock(); } } } } //线程3 static class ThreadC extends Thread{ @Override public void run(){ for (int i = 0; i < 10; ) { lock.lock(); try { if (state % 3 == 2){ System.out.println(Thread.currentThread().getName() + "C"); state++; i++; } }finally { lock.unlock(); } } } } public static void main(String[] args) { new ThreadA().start(); new ThreadB().start(); new ThreadC().start(); } }
运行结果如下:
可以看到是按照顺序执行的奥。
再来个锁的例子
/** * @version 1.0 * @date 2021/5/16 * Lock提供条件Condition,对线程的等待和唤醒更加详细和灵活 * * 内部维护一个Condition队列。当前线程调用await方法后,将会以当前线程构造为一个结点Node,并将该节点放到该队列的尾部 * * Condition是个接口,基本的方法就是await()和signal()方法; * Condition依赖于Lock接口,生成一个Condition的方式是lock.newCondition() */ public class Concurrent03 { private int count; private final Lock lock = new ReentrantLock(); private final Condition condition = lock.newCondition(); public static void main(String[] args) { Concurrent03 c = new Concurrent03(); ExecutorService service = Executors.newCachedThreadPool(); service.execute(c::printA); service.execute(c::printB); service.execute(c::printC); service.shutdown(); } public void printA() { lock.lock(); try { while (true){ if (count % 3 != 0) { condition.await(); } Thread.sleep(300); System.out.print("A "); count ++; condition.signalAll(); } } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public void printB() { lock.lock(); try { while (true){ if (count % 3 != 1) { condition.await(); } Thread.sleep(300); System.out.print("B "); count ++; condition.signalAll(); } } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } public void printC() { lock.lock(); try { while (true){ if (count % 3 != 2) { condition.await(); } Thread.sleep(300); System.out.print("C "); count ++; condition.signalAll(); } } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } } }
运行结果:
可以看到按顺序打印了 A B C …
完