多个线程之间的控制,最基本的就是相互之间的wait(),notify()等。其实java.util.concurrent类中已经有了好多同步辅助类,需要的时候感觉还是很好用的。用法整理一下,走起!
1.Semaphore:
就叫它信号量吧。举个栗子就知道它是干啥的了。
new Semaphore(int
)。创建了一个自助提款站点,参数代表此站点有几个ATM机。
一个线程来了,调用semaphore.acquire(),占了一个ATM机。又来一个线程来占用ATM... 直到所有ATM都被占用后,再来线程调用semaphore.acquire(),那么这个线程就必须等待。直到其中有一个线程使用完毕,调用semaphore.release(),前面等待的线程才会停止等待,继续执行下去。
测试代码:
private void initSemaphore() throws InterruptedException {
//这里只分配两个信号量,下面三个线程总会有一个抢不到,只能等待其他线程释放掉其信号。
mSemaphore = new Semaphore(2);
for (int i = 0; i < 3; i++) {
final String threadName = i + "";
new Thread() {
@Override
public void run() {
super.run();
long l = System.currentTimeMillis();
try {
<span style="color:#ff0000;">mSemaphore.acquire();</span>
} catch (InterruptedException e) {
e.printStackTrace();
}
SystemClock.sleep(2000);
Log.e(TAG, "Thread num is " + threadName + " is run!" + "Wait time:" + (System.currentTimeMillis() - l));
<span style="color:#ff0000;">mSemaphore.release();</span>
}
}.start();
}
Log.e(TAG, "Threads run over");
}
执行结果:
E/TAG: Threads run over
E/TAG: Thread num is 2 is run!Wait time:2000
E/TAG: Thread num is 0 is run!Wait time:2001
E/TAG: Thread num is 1 is run!Wait time:3999
可以看到,Thread num 为1 的线程运行时间成了4秒,因为它第一次没有抢到信号量,所以要等待其余两个线程释放信号量,它才会继续执行。
2.CountDownLatch
这个和上面那个有点相类似,还是来个栗子:new CountDownLatch(int)。创建一个旅游活动,参数表示这个活动最少需要多少成员,活动才能顺利进行下去。
某个线程报到(调用countDownLatch.countDown()方法)。当没有达到最低数量要求,一些调用了countDownLatch.await()方法的线程会在此方法等待,直到报到的数量达到最低要求。
测试代码:
private void initCountDownLatch() throws InterruptedException {
mCountDownLatch = new CountDownLatch(3);
long l = System.currentTimeMillis();
for (int i = 0; i < 3; i++) {
final String threadName = i + "";
new Thread() {
@Override
public void run() {
super.run();
SystemClock.sleep(2000);
Log.e(TAG, "Thread num is " + threadName + " is run!");
<span style="color:#ff0000;">mCountDownLatch.countDown();</span>
}
}.start();
}
<span style="color:#ff0000;">mCountDownLatch.await()</span>;
Log.e(TAG, "Threads run over "+(System.currentTimeMillis()-l));
/*下面的方法
1.当到指定时间后,上面线程没有全部执行完,不再等待。return false;
2.当到指定时间前,上面线程全部执行完了,则不再等待。return true;
3.当被打断,抛异常。
*/
// boolean result = mCountDownLatch.await(1000, TimeUnit.MILLISECONDS);
//boolean result = mCountDownLatch.await(4000, TimeUnit.MILLISECONDS);
//Log.e(TAG, "Threads run over result is " + result + " time is " + (System.currentTimeMillis() - l));
}
执行结果:
E/TAG: Thread num is 0 is run!
E/TAG: Thread num is 2 is run!
E/TAG: Thread num is 1 is run!
E/TAG: Threads run over 2021
可以看到,主线程会等待countDown()调用够3次后,await()方法才往下执行。
下面注释的带参数的几个方法意思是:设置等待时间,不管有没达到数量要求,到时间就不再等待。当然,如果没有达到要求会返回false,反之返回true。
下面是参数为4000ms的执行结果:
E/TAG: Thread num is 2 is run!
E/TAG: Thread num is 1 is run!
E/TAG: Thread num is 0 is run!
E/TAG: Threads run over result is true time is 2017
可以看到,当在设置时间前完成,这个参数是没有什么意义的,返回为true。
下面是参数为1000ms的执行结果:
E/TAG: Threads run over result is false time is 1004
E/TAG: Thread num is 0 is run!
E/TAG: Thread num is 2 is run!
E/TAG: Thread num is 1 is run!
可以看到,当在设置时间前没有
完成,不再等待,返回为false
3.CyclicBarrier
这个和上面的countDownLatch相似,上面是让某一个线程等待多个线程。这个是多个线程互相等待某一件事发送,才继续下去。
new CyclicBarrier(4):这个意思是,对所有await的调用线程都会等待,直到await的次数达到指定值,此时,所有await的线程立即被唤醒。
测试代码:
private void initCyclicBarrier() {
mCyclicBarrier = new CyclicBarrier(4);
for (int i = 0; i < 3; i++) {
final String threadName = i + "";
new Thread() {
@Override
public void run() {
super.run();
Log.e(TAG, "Thread num is " + threadName + " is wait!");
try {
<span style="color:#ff0000;"> int result = mCyclicBarrier.await();
//int result = mCyclicBarrier.await(2000, TimeUnit.MILLISECONDS);
</span> // Log.e(TAG, "Thread num is " + threadName + " is over " + result);
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
} //catch (TimeoutException e) {
// e.printStackTrace();
// <span style="color:#ff0000;">Log.e(TAG, "TimeoutException");</span>
// }
}
}.start();
}
}
执行结果:
E/TAG: Thread num is 0 is wait!
E/TAG: Thread num is 1 is wait!
E/TAG: Thread num is 2 is wait!
E/TAG: Thread num is 2 is over
E/TAG: Thread num is 0 is over
E/TAG: Thread num is 1 is over
可以看到,等3个都await后,才集体被唤醒,执行over。
其中带参数的await方法,是等待超时时间,如果等待超时,直接抛出TimeOutException。
4.Phaser
算是CountDownLatch和CyclicBarrier 的合体,但也有改进。
举个栗子:一个任务有3个线程去并发执行,这个任务可以分为4个阶段,并且每个阶段结束,才能进行下个阶段。
那么new Phaser(3),就是三个线程并发执行。三个线程执行调用arriveAndAwaitAdvance()方法,这个方法会等待,直到执行arriveAndAwaitAdvance()方法到达3个后(意思就是当前阶段全部结束,可以进行下个阶段了),都被唤醒,继续执行。
测试代码:
private void initPhaser() {
//三个线程来执行
int threads = 3;
//4个阶段
final int phaser = 4;
mPhaser = new Phaser(<span style="color:#ff0000;">threads</span>);
for (int i = 0; i < 3; i++) {
final String threadName = i + "";
new Thread() {
@Override
public void run() {
super.run();
for (int phase = 0; phase < phaser; phase++) {
Log.e(TAG, "Thread num is " + threadName + "phase is " + phase);
<span style="color:#ff0000;">mPhaser.arriveAndAwaitAdvance();</span>
}
}
}.start();
}
}
执行结果:
E/TAG: Thread num is 0phase is 0
E/TAG: Thread num is 1phase is 0
E/TAG: Thread num is 2phase is 0
E/TAG: Thread num is 1phase is 1
E/TAG: Thread num is 2phase is 1
E/TAG: Thread num is 0phase is 1
E/TAG: Thread num is 1phase is 2
E/TAG: Thread num is 0phase is 2
E/TAG: Thread num is 2phase is 2
E/TAG: Thread num is 1phase is 3
E/TAG: Thread num is 2phase is 3
E/TAG: Thread num is 0phase is 3
可以看到,arriveAndAwaitAdvance()方法,在到达设定值之前会一直等待。