目标:创建4个线程分别为thread1,thread2,thread3,thread4让这三个线程依次执行。
方法一:join
public class ThreadSequence {
//线程1 ----------------------》
static Thread thread1 = new Thread(()->{
System.out.println(Thread.currentThread().getName()+"启动了------》");
},"线程t1");
//线程2 ----------------------》
static Thread thread2 = new Thread(()->{
System.out.println(Thread.currentThread().getName()+"启动了------》");
},"线程t2");
//线程3 ----------------------》
static Thread thread3 = new Thread(()->{
System.out.println(Thread.currentThread().getName()+"启动了------》");
},"线程t3");
//线程4 ----------------------》
static Thread thread4 = new Thread(()->{
System.out.println(Thread.currentThread().getName()+"启动了------》");
},"线程t4");
public static void main(String[] args) throws Exception{
/*代码解释:
* 程序main线程中调用thread1线程的join方法,则main线程会放弃CPU,返回给thread1,直到thread1执行完毕。
* 所以是thread1线程执行完后,才到主线程执行,相当于在main线程中同步thread1线程,thread1执行完了,main线程才有执行的机会
* */
thread1.start();
thread1.join();//join代表让主线程即main线程,等待子线程运行结束后才继续执行
thread2.start();
thread2.join();
thread3.start();
thread3.join();
thread4.start();
thread4.join();
}
}
未添加join方法时,执行结果是乱序的
增加join方法后,执行结果是顺序的
分析join源码
/**
* Waits at most {@code millis} milliseconds for this thread to
* die. A timeout of {@code 0} means to wait forever.
*
* <p> This implementation uses a loop of {@code this.wait} calls
* conditioned on {@code this.isAlive}. As a thread terminates the
* {@code this.notifyAll} method is invoked. It is recommended that
* applications not use {@code wait}, {@code notify}, or
* {@code notifyAll} on {@code Thread} instances.
*
* @param millis
* the time to wait in milliseconds
*
* @throws IllegalArgumentException
* if the value of {@code millis} is negative
*
* @throws InterruptedException
* if any thread has interrupted the current thread. The
* <i>interrupted status</i> of the current thread is
* cleared when this exception is thrown.
*/
public final synchronized void join(long millis)
throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
/**
* Tests if this thread is alive. A thread is alive if it has
* been started and has not yet died.
*
* @return <code>true</code> if this thread is alive;
* <code>false</code> otherwise.
*/
public final native boolean isAlive();
源码中的参数millis默认值是0,从英文注释翻译后可以找到,0秒意味着永远等待,也就是thread1执行不完,那主线程你就要一直等着,一直wait,而代码中wait方法其实就是属于Object的方法,负责线程的休眠等待,当main主线程调用thread1.join的时候,main主线程会获得线程对象thread1的锁(wait 意味着拿到该对象的锁),调用该对象的wait(等待时间),直到该对象唤醒main主线程 ,比如退出后。这就意味着main 线程调用thread1.join时,必须能够拿到线程thread1对象的锁。
这里有一个**isAlive()**方法很重要。判断当前线程是否处于活动状态。活动状态就是线程启动且尚未终止,比如正在运行或准备开始运行。
所以从代码上看,如果线程被生成了,但还未被起动,调用它的 join() 方法是没有作用的,将直接继续向下执行。
在Object.java中,wait()的作用是让当前线程进入等待状态,同时,wait()也会让当前线程释放它所持有的锁。
所以Join()主要就是通过wait()方法来实现这个目的的。
方法二:ExecutorService()的newSingleThreadExecutor()
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class ExecutorServiceSequence {
static ExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
//线程1 ----------------------》
static Thread thread1 = new Thread(()->{
System.out.println("启动了线程t1------》");
});
//线程2 ----------------------》
static Thread thread2 = new Thread(()->{
System.out.println("启动了线程t2------》");
});
//线程3 ----------------------》
static Thread thread3 = new Thread(()->{
System.out.println("启动了线程t3------》");
});
//线程4 ----------------------》
static Thread thread4 = new Thread(()->{
System.out.println("启动了线程t4------》");
});
public static void main(String[] args) {
executorService.submit(thread1);
executorService.submit(thread2);
executorService.submit(thread3);
executorService.submit(thread4);
executorService.shutdown();
}
}
执行结果
这种方式的原理其实就是将线程用排队的方式扔进一个线程池里,newSingleThreadScheduledExecutor实例化的对象一次只有一个线程执行,让所有的任务以单线程的模式,按照FIFO先进先出、LIFO后进先出、优先级等特定顺序执行,但是这种方式也是存在缺点的,就是当一个线程被阻塞时,其它的线程都会受到影响被阻塞,不过依然都会按照自身调度来执行,只是会存在阻塞延迟。
参考文章
https://www.cnblogs.com/panda001/p/12363532.html
https://www.jianshu.com/p/481c01528bdb
https://www.cnblogs.com/xieshengdev/p/10082787.html