之前看到个问题,如果有3个线程,如何保证3个线程的执行先后顺序。其实实现的方法有很多,这里主要介绍几种。
首先,线程Thread有一个设置优先级的属性Priority,默认数值为5,设置的越高优先级越高,最高为10。但是这里需要注意的是:
优先级作用只是表示了执行的概率,也就是说优先级6的线程比5的线程概率更高,但不代表一定就优先执行。
(一)首先说下第一种方法,线程池ExecutorService有一个工厂方法newSingleThreadExecutor(),该方法生成的是单例线程,因此如果向其提交线程时,先提交的先执行,后提交的执行,以此就能实现执行顺序。
代码:
ExecutorService es = Executors.newSingleThreadExecutor();
es.submit(new Runnable() {
@Override
public void run() {
System.out.println("C");
}
});
es.submit(new Runnable() {
@Override
public void run() {
System.out.println("B");
}
});
es.submit(new Runnable() {
@Override
public void run() {
System.out.println("A");
}
});
es.shutdown();
结果:C B A
(二)concurrent包里面有个CountDownLatch计数器,这里面有2个方法:c.countDown():作用是计数器减1,c1.await(),如果计数器暂时没有到0,则阻塞线程。
代码:
System.out.println("begin");
CountDownLatch c1 = new CountDownLatch(1);
CountDownLatch c2 = new CountDownLatch(1);
CountDownLatch call = new CountDownLatch(3);
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
c2.await();
System.out.println("A");
call.countDown();
}catch (Exception e){
e.printStackTrace();
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
c1.await();
System.out.println("B");
c2.countDown();
call.countDown();
}catch (Exception e){
e.printStackTrace();
}
}
});
Thread t3 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("C");
c1.countDown();
call.countDown();
}
});
t1.start();
t2.start();
t3.start();
try {
call.await();
}catch (Exception e){
e.printStackTrace();
}
结果 :C B A
(三)栅拦CyclicBarrier
CyclicBarrier同样也是concurrent包里的类,有2个构造函数,并且有一个await()方法,其目的是所有调用await()方法的线程都会被CyclicBarrier拦截,直到拦截的线程数量达到了CyclicBarrier的要求,然后统一一起执行。
代码:
public static void main(String[] args) {
CyclicBarrier cb = new CyclicBarrier(4);
ExecutorService es = Executors.newCachedThreadPool();
for (int i=0;i<4;i++) {
es.submit(new RClass(cb,i));
}
es.shutdown();
}
}
class RClass implements Runnable{
private CyclicBarrier cb;
private Integer count;
RClass(CyclicBarrier cb,Integer count){
this.cb = cb;
this.count = count;
}
@Override
public void run() {
System.out.println("begin:"+count);
try {
cb.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println("after:"+count);
}
显示的结果:
begin:0
begin:1
begin:2
begin:3
after:3
after:0
after:1
after:2
这里需要注意的是:1、如果线程数量小于栅栏设置的数量,则所有线程都会一直阻塞;2、如果线程的数量大于设置的数量n,则会先把这N个线程执行了,剩下的继续拦截,除非剩下的又能满足N。从这也可以栅栏的好处,设置的CyclicBarrier 可以重复使用。