如何使多个线程顺序执行(海拍客面试篇)

问题:假设当前有四个线程,分别是A,B,C,D四个线程,假设现在设计一个程序,让A,B,C,D四个线程一次输出A,B,C,D,循环十次。

当时面试过程中稍微有点紧张,虽然是面试实习生的岗位,可怕的是居然面试了三轮技术面。可能因为海拍客是小独角兽的原因吧。
好了,言归正传。这本来是一个比较简单的问题,说白了就是线程同步。线程同步的话也就那几种,Synchronized,Lock锁,阻塞队列这些东东。因为是现场面试的,所以要手写出来,但是一上手的时候发现貌似不好写啊,感觉不是那么回事。但是即使没写出来,后面面试也侥幸通过了。可能是因为前面基础知识回答的还行吧,嘿嘿!!

话不多说,现在让我们看看怎么来实现这个程序吧。以下有五种方式进行实现:

  • 利用主线程的join()或者子线程的run()方法实现。(下面例子以主线程join()为主)
    public static void main(String args[]){
    Thread A = new Thread(new Runnable(){
    public void run(){
    System.out.print(“A”);
    }
    });
    Thread B = new Thread(new Runnable(){
    public void run(){
    System.out.print(“B”);
    }
    });
    Thread C = new Thread(new Runnable(){
    public void run(){
    System.out.print(“C”);
    }
    });
    Thread D = new Thread(new Runnable(){
    public void run(){
    System.out.print(“D”);
    }
    });

for(int i=0;i<10;i++){
A.start();A.join();
B.start();B.join();
C.start();C.join();
D.start();D.join();
}
}

我们知道在程序中使用线程一般不会单个创建和销毁,因为单个线程创建比较耗费资源,所以会复用线程,利用线程池来实现。

  • 线程池实现线程顺序执行
    Java通过Executors提供的线程池有四种,分别是
    (1) 单线程化线程池(newSingleThreadExecutor);
    (2) 可控最大并发数线程池(newFixedThreadPool);
    (3) 可回收缓存线程池(newCachedThreadPool);
    (4) 支持定时和周期任务的线程池(newScheduled);

    newSingleThreadExecutor串行执行所有任务,通过submit()提交任务,shutdown()关闭线程池,拒绝新任务。应用于所有任务的执行顺序按照线程提交顺序执行。
    public static void main(String args[]){
    Thread A = new Thread(new Runnable(){
    public void run(){
    System.out.print(“A”);
    }
    });
    Thread B = new Thread(new Runnable(){
    public void run(){
    System.out.print(“B”);
    }
    });
    Thread C = new Thread(new Runnable(){
    public void run(){
    System.out.print(“C”);
    }
    });
    Thread D = new Thread(new Runnable(){
    public void run(){
    System.out.print(“D”);
    }
    });
    static ExecutorService executorservice = Executors.newSingleThreadExecutor();
    for(int i=0;i<10;i++){
    executorservice.submit(A);
    executorservice.submit(B);
    executorservice.submit©;
    executorservice.submit(D);
    }
    executorservice.shutdown();
    }

  • 通过java.util.Concurrent包下的CountDownLatch(倒计数)实现线程顺序执行。
    public static void main(String args[]){
    //初始化倒计数器的初值为1,每次调用countDown()方法,倒计数器会-1,调用await()方法进行阻塞,当倒计数器值为0时唤醒往下执行。
    private static CountDownLatch c1 = new CountDownLatch(1);
    private static CountDownLatch c2 = new CountDownLatch(1);
    private static CountDownLatch c3 = new CountDownLatch(1);

Thread A = new Thread(new Runnable(){
public void run(){
System.out.print(“A”);
c1.countDown();
}
});
Thread B = new Thread(new Runnable(){
public void run(){
c1.await();
System.out.print(“B”);
c2.countDown();
}
});
Thread C = new Thread(new Runnable(){
public void run(){
c2.await();
System.out.print(“C”);
c3.countDown();
}
});
Thread D = new Thread(new Runnable(){
public void run(){
c3.await();
System.out.print(“D”);
}
});
}

  • 通过CyclicBarrier(回环栅栏)使线程顺序执行。回环栅栏可以实现让一组线程等待至某个状态后在全部同时执行。叫做回环的原因是当所有线程释放后,cyclicbarrier可以重用。我们将这个状态称为barrier,当线程中调用CyclicBarrier的await()方法后,线程就处于barrier状态了。

public static void main(String args[]){

//new CyclicBarrier(n),n代表当前栅栏中线程个数。
static CyclicBarrier barrier1 = new CyclicBarrier(2);
static CyclicBarrier barrier2 = new CyclicBarrier(2);
static CyclicBarrier barrier3 = new CyclicBarrier(2);

Thread A = new Thread(new Runnable(){
public void run(){
System.out.print(“A”);
barrier1.await();
}
});
Thread B = new Thread(new Runnable(){
public void run(){
barrier1.await();
System.out.print(“B”);
barrier2.await();
}
});
Thread C = new Thread(new Runnable(){
public void run(){
barrier2.await();
System.out.print(“C”);
barrier3.await();
}
});
Thread D = new Thread(new Runnable(){
public void run(){
barrier3.await();
System.out.print(“D”);
}
});

A.start();
B.start();
C.start();
D.start();

}

  • 通过Sephmore(信号量)使线程顺序执行。Sephmore(信号量)是一个计数信号量,sephmore包含一组许可证,如果需要的话,每个acquire()方法都会阻塞,直到获取一个可用的许可证,每个release()方法都会释放持有许可证的线程,并且归还Sephmore一个可用的许可证,其实sephmore就是对可用的数量进行管理。

acquire():当前线程尝试去阻塞的获取1个许可证,此过程是阻塞的,当前线程获取了一个可用的许可证,就会停止等待,继续执行。
release():当前线程释放一个有用的许可证。

public static void main(String args[]){

private static Semaphore semaphore1 = new Semaphore(1);
private static Semaphore semaphore2 = new Semaphore(1);
private static Semaphore semaphore3 = new Semaphore(1);

final Thread A = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(“A”);
semaphore1.release();
}
});
final Thread B = new Thread(new Runnable() {
@Override
public void run() {
semaphore1.acquire();
System.out.println(“B”);
semaphore2.release();
}
});
final Thread C = new Thread(new Runnable() {
@Override
public void run() {
semaphore2.acquire();
System.out.println(“C”);
semaphore3.release();
}
});
final Thread D = new Thread(new Runnable() {
@Override
public void run() {
semaphore3.acquire();
System.out.println(“D”);
}
});
}

你可能感兴趣的:(并发编程)