目录
CyclicBarrier作用就是会让所有线程都等待完成后才会继续下一步行动。
Java5中添加了障碍器类,为了适应一种新的设计需求,比如一个大型的任务,常常需要分配好多子任务去执行,只有当所有子任务都执行完成时候,才能执行主任务,这时候,就可以选择障碍器了。障碍器是多线程并发控制的一种手段
CyclicBarrier(int parties)参与线程的个数
CyclicBarrier(int parties, Runnable barrierAction)
Runnable参数是最后一个到达线程要做的任务int await() 线程调用await()表示自己已经到达栅栏
int await(long timeout, TimeUnit unit)
主要工作原理,通过构造函数创建一个指定屏障数的屏障类,在各线程中调用await(),调用后当前线程将被阻塞,直到调用的次数到指定屏障数后,所有阻塞的线程将恢复继续执行。
CountDownLatch闭锁
CountDownLatch是一个同步工具类,join的增强版。允许一个或多个线程,等待其他一组线程完成操作,再继续执行。底层实现为AQS
public CountDownLatch(int count); 构造函数,初始化计数器值为count,count只能被设置一次
public void await()throws InterruptedException; 调用await()方法的线程会被挂起,直到count值为0才继续执行
public boolean await(longtimeout, TimeUnit unit)throws InterruptedException; 和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
public void countDown();将count值减1
它是通过控制计数器的值来达到等待的目的。当计数器的值>0时,调用countDownLatch.await()会阻塞当前线程,直到其他线程调用countDownLatch.countDown()将计数器的值减到0时,阻塞线程将被唤醒。计数器的值>0时调用await()方法不会阻塞当前线程。主线程必须在启动其他线程后立即调用CountDownLatch.await()方法。这样主线程的操作就会在这个方法上阻塞,直到其他线程完成各自的任务。
join与countDownLatch区别
join用于让当前执行线程等待join线程执行结束。其实现原理是不停检查join线程是否存活,如果join线程存活则让当前线程永远wait。
countDownLatch没有这个线程,只要count减小到0,不管被等待线程是否执行结束,等待线程都可以继续执行(被唤醒,进入可执行状态)。
yield与join方法的区别
yield()方法:暂停当前正在执行的线程对象,并执行其他线程。
yield()应该做的是让当前运行线程回到可运行状态,以允许具有相同优先级的其他线程获得运行机会。因此,使用yield()的目的是让相同优先级的线程之间能适当的轮转执行。但是,实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。
yield暂停正在执行的线程
Thread.yield()方法作用是:暂停当前正在执行的线程对象,并执行其他线程。
主要目的在于避免线程饥饿问题
yield()应该是让当前运行线程回到可运行状态以允许具有相同优先级的其他线程获得运行机会。因此,使用yield()的目的是让相同优先级的线程之间能适当的轮转执行。但是实际中无法保证yield()达到让步目的,因为让步的线程还有可能被线程调度程序再次选中。
结论:yield()从未导致线程转到等待/睡眠/阻塞状态。在大多数情况下,yield()将导致线程从运行状态转到可运行状态,但有可能没有效果
public class Test11 {
public static void main(String[] args) {
final Object obj = "1111";
Runnable runnable = new Runnable() {
public void run() {
synchronized (obj) {
for (int i = 0; i < 10; i++) {
System.out.println("当前线程为: " + Thread.currentThread().getName() + "--->" + i);
if (i == 5)
Thread.yield();
}
}
}
};
Thread thread = new Thread(runnable, "A");
Thread thread1 = new Thread(runnable, "B");
thread.start();
thread1.start();
}
}
join阻塞当前线程等待线程
t.join()方法阻塞调用此方法的线程(calling thread)进入TIMED_WAITING状态,直到线程t完成,此线程再继续;通常用于在main()主线程内,等待其它线程完成再结束main()主线程
Join方法实现是通过wait()。 当main线程调用t.join时候,main线程会获得线程对象t的锁(wait意味着拿到该对象的锁),调用该对象的wait(),直到该对象唤醒main线程 ,比如退出后。这就意味着main线程调用t.join时,必须能够拿到线程t对象的锁。
public class Test12 {
@SuppressWarnings("static-access")
public static void main(String[] args) throws Exception {
final Object obj = "1111";
Thread thread = new Thread(new Runnable() {
public void run() {
synchronized (obj) {
for (int i = 0; i < 10; i++) {
System.out.println("当前线程为: " + Thread.currentThread().getName() + "--->" + i);
}
}
}
}, "A");
Thread thread1 = new Thread(new Runnable() {
public void run() {
synchronized (obj) {
for (int i = 0; i < 10; i++) {
System.out.println("当前线程为: " + Thread.currentThread().getName() + "--->" + i);
if (i == 5)
try {
thread.join();
// obj.wait(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}, "B");
thread1.start();
Thread.currentThread().sleep(1);
thread.start();
}
}
结论:
yield()从未导致线程转到等待/睡眠/阻塞状态。在大多数情况下,yield()将导致线程从运行状态转到可运行状态,但有可能没有效果。
join()方法:线程实例的join()方法可以使得一个线程在另一个线程结束后再执行,即也就是说使得当前线程可以阻塞其他线程执行;
thread.Join把指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程。比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。