您的位置:首页 > 其它

多线程控制、同步的几个实用的类

2016-06-24 21:35 302 查看
多个线程之间的控制,最基本的就是相互之间的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
4000
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()方法,在到达设定值之前会一直等待。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  多线程 同步