今天面试美团,面试官提出了一个多线程方面的问题,自己只回答了一方面,下来后自己查看了一下,还有一种其他的方法,现在记录一下。
最容易想到的就是thread的join方法,通过在一个线程里调用另一个线程的join方法,可以让当前线程等待另一个线程完成之后在执行方法体;
其次就是CountDownLatch,调用CountDownLatch的await方法时,需要等到该CountDownLatch的值为0时,才能执行往后的方法体,这样的话,可以将CountDownLatch作为传参加入线程中,控制线程的执行流程;
还有就是CyclicBarrier,作用类似与CountDownLatch,但是又有一些不同,CountDownLatch的作用是让一个线程等待其他一个或N个线程完成之后,CountDownLatch的值为0的时候,当前线程才可以执行,CyclicBarrier的作用是让所有线程到达同一个屏障(或者叫同步点)时,所有被拦截的线程才可以继续往下执行,CountDownLatch只能使用一次,CyclicBarrier可以循环使用(调用reset方法);
线程池方法,使用newSingleThreadExecutor,一般开发中不建议用Executors,因为默认设置的工作队列是无界队列,所以容易出现资源耗尽的情况,尽量用原生ThreadPoolExecutor构造函数去创建;
Sychronized,用加锁的方法同样可以对线程的执行顺序进行保证
具体代码如下:
1,thread.join()
首先定义工作线程WorkThread
public class WorkThread implements Runnable {
private ThreadbeforeThread;
public WorkThread(Thread beforeThread) {
this.beforeThread = beforeThread;
}
@Override
public void run() {
if(beforeThread !=null){
try{
beforeThread.join();
System.out.println(Thread.currentThread().getName() +"启动");
}catch (Exception e){
e.printStackTrace();
}
}else{
System.out.println(Thread.currentThread().getName() +"启动");
}
}
}
接下来在main方法里定义几个线程执行一下。
public static void main(String[] args) {
Thread thread1=new Thread(new WorkThread(null));
thread1.setName("线程1");
Thread thread2=new Thread(new WorkThread(thread1));
thread1.setName("线程2");
Thread thread3=new Thread(new WorkThread(thread2));
thread1.setName("线程3");
//三个线程的start顺序任意,执行顺序不变
thread1.start();
thread2.start();
thread3.start();
}
这里三个thread的start顺序可以任意写,结果是一样的。
线程1启动
线程2启动
线程3启动
2,CountDownLatch
同样,首先定义工作线程
public class WorkThread implements Runnable {
private CountDownLatch c1;
private CountDownLatch c2;
public WorkThread(CountDownLatch c1, CountDownLatch c2) {
this.c1 = c1;
this.c2 = c2;
}
@Override
public void run {
try{
c1.await();
System.out.println(Thread.currentThread().getName() +"启动");
c2.countDown();
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
同样,测试一下。
public static void main(String[] args) {
CountDownLatch c1 = new CountDownLatch(0);
CountDownLatch c2 = new CountDownLatch(1);
CountDownLatch c3 = new CountDownLatch(1);
Thread thread1 = new Thread(new WorkThread(c1,c2));
thread1.setName("线程1");
Thread thread2 = new Thread(new WorkThread(c2,c3));
thread2.setName("线程2");
Thread thread3 = new Thread(new WorkThread(c3,c3));
thread3.setName("线程3");
thread1.start();
thread2.start();
thread3.start();
}
这里三个thread的start顺序可以任意写,结果是一样的。
线程1启动
线程2启动
线程3启动
3,CyclicBarrier
同样,首先定义工作线程
public class WorkThread implements Runnable {
private CyclicBarrier c1;
private CyclicBarrier c2;
public WorkThread(CyclicBarrier c1, CyclicBarrier c2) {
this.c1 = c1;
this.c2 = c2;
}
@Override
public void run {
try{
c1.await();
System.out.println(Thread.currentThread().getName() +"启动");
c2.await();
}catch (Exception e){
e.printStackTrace();
}
}
}
同样,测试一下。
public static void main(String[] args) {
CyclicBarrier c1 = new CyclicBarrier (1);
CyclicBarrier c2 = new CyclicBarrier (2);
CyclicBarrier c3 = new CyclicBarrier (2);
Thread thread1 = new Thread(new WorkThread(c1,c2));
thread1.setName("线程1");
Thread thread2 = new Thread(new WorkThread(c2,c3));
thread2.setName("线程2");
Thread thread3 = new Thread(new WorkThread(c3,c3));
thread3.setName("线程3");
thread1.start();
thread2.start();
thread3.start();
}
这里三个thread的start顺序可以任意写,结果是一样的。
线程1启动
线程2启动
线程3启动
4,线程池
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
Thread thread1 = new Thread();
thread1.setName("线程1");
Thread thread2 = new Thread();
thread2.setName("线程2");
Thread thread3 = new Thread();
thread3.setName("线程3");
executorService .submit(thread1);
executorService .submit(thread2);
executorService .submit(thread3);
executorService .shutdown();
}
这里三个thread的start顺序可以任意写,结果是一样的。
线程1启动
线程2启动
线程3启动
5,Synchronized
class WorkThread implements Runnable {
private Param param;
private String name;
private int process;
public WorkThread(Param param,String name,int process) {
this.param = param;
this.name = name;
this.process = process;
}
@Override
public void run() {
synchronized (param) {
int state =param.getState();
while (state !=process) {
try {
param.wait();
}catch (InterruptedException e) {
e.printStackTrace();
}
state =param.getState();
}
System.out.println(name +" thread is running");
param.setState(++state);
param.notifyAll();
}
}
}
class Param {
private int state =0;
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
}
在main方法测试一下,结果是一样的
public static void main(String[] args) {
Param param =new Param();
Thread t1 =new Thread(new WorkThread(param,"t1",0));
Thread t2 =new Thread(new WorkThread(param,"t2",1));
Thread t3 =new Thread(new WorkThread(param,"t3",2));
t3.start();
t2.start();
t1.start();
}
输出如下:
t1 thread is running
t2 thread is running
t3 thread is running
暂时先写这些方法,往后有补充的再写上,要保证线程执行顺序,只要涉及多线程之间的通信的方法,应该是都可以实现的,实现方法多种多样。