Java并发编程-Synchronizers

本文详细介绍了Java中的三大同步工具类:Latch、Semaphore、Barrier的功能、应用场景及区别,并通过示例代码展示了它们的实际使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Latch,Semaphore,Barrier是java中的三大同步工具类。首先了解下他们的特性和应用场景:{ps:有些东西纯属个人理解,有不正确的地方请指教}


 Latch(门闩):闭锁是一个同步工具类,可以延迟线程执行直到所有的线程都到达一个状态。
 作用:

  1、确保某个计算在其所需要的所有资源都初始化后再执行;
  2、确保某个服务在其他所依赖的服务都执行完毕后再执行;
  3、等个某个操作的所有参与者都准备就绪后再继续执行。


 信号量:信号量用来控制同时访问资源和执行当前动作的线程个数
 信号量应用场景:

 1、实现资源池,如数据库连接池;
 2、将任意collection 转换成有界的阻塞collection
 3、单个信号量的Semaphore对象可以实现互斥锁,而且可以由一个线程锁定,另外一个线程释放,是解决死锁的一种方法


Barrier(障碍):Barrier等待一组活动都完成或者一组活动都开始后再执行线程的后续操作,如组织去公园,等人到齐了才出发
Barrier跟Latch区别:

 1、Barrier的定义是所有线程都得到达同一点才能继续向下执行,Latch的定义是当Latch达到一个 临界(终点)状态时所有的线程才能获得往下执行的通道。
 2、Latch是线程等待某个事件完成,Barrier是线程等待其他线程
 3、个人理解觉得Latch是被动等待,Barrier是主动等待。Barrier等待方会被等待方是同一属性级别,都是线程。如自发组织旅游,所有人按约定 的时间,地点在同一个地方集合,先到的人等待其他人都到齐后再一起出发。Latch就像开会签到,开会前参与者先进行签到,当组织者等到所有参与者都签到
 后再进入会议主题

下面是三种同步工具类的Demo以及测试代码:

Latch:

package cn.com.chp5.latch;

import java.util.concurrent.CountDownLatch;

/**
 * <th>Latch例子<th>
 * 
 * <p>
 * 功能:通过CountDownLatch begin事件触发线程等待,当所有子线程全部准备就绪后再开始执行线程,当所有子线程执行完毕后的end触发主线程
 * 整个功能完成记录所有子线程从就绪到执行完的执行时间记录
 * <p>
 * 
 * <p>
 * Latch(门闩):闭锁是一个同步工具类,可以延迟线程执行直到所有的线程都到达一个状态。
 * 作用:1、确保某个计算在其所需要的所有资源都初始化后再执行;
 * 2、确保某个服务在其他所依赖的服务都执行完毕后再执行;
 * 3、等个某个操作的所有参与者都准备就绪后再继续执行。
 * <p>
 * 
 * @author tianxingjian <h1>date: 2014-01-16</h1>
 */
public class LatchDemo {
	public Long runTask(int threadNum, final Runnable runnable) throws InterruptedException{
		final CountDownLatch begin = new CountDownLatch(1);
		final CountDownLatch end = new CountDownLatch(threadNum);
		
		for(int i = 0; i < threadNum; i++){
			Thread th = new Thread(){
				public void run(){
					try{
						begin.await();
						try {
							runnable.run();
						}finally{
							end.countDown();
						}
					}
					catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			};
			th.start();
		}
		Long beginSec = System.nanoTime();
		//begin 和end顺序千万不能写错,不然程序就死锁了。
		begin.countDown();
		end.await();
		Long endSec = System.nanoTime();
		
		return endSec - beginSec;
	}
}

package cn.com.chp5.latch;

import java.util.Random;

public class LatchTest {
	private static final int count = 10;
	public static void main(String[] args) throws InterruptedException {
		System.out.println("进入主线程:。。。。。。");
		Long l = new LatchDemo().runTask(count, new TaskAction());
		System.out.println("工作线程执行时间:" + l);
	}
	
}
class TaskAction implements Runnable{

	@Override
	public void run() {
		Random rand = new Random(1000);
		int count = rand.nextInt() + 1;
		for(int i = 0; i < count; i++){
			int result = i*i;
		}
	}
	
}

Semaphore:

package cn.com.chp5.semaphore;

import java.util.concurrent.Semaphore;

/**
 * <th>Semaphore例子<th>
 * 
 * <p>
 * 预期结果:线程可以启动多个,但是同时执行aquireAction的线程最多count个
 * <p>
 * 
 * <p>
 * 信号量作用:信号量用来控制同时访问资源和执行当前动作的线程个数
 * 信号量应用场景:1、实现资源池,如数据库连接池;
 * 2、将任意collection 转换成有界的阻塞collection
 * 3、单个信号量的Semaphore对象可以实现互斥锁,而且可以由一个线程锁定,另外一个线程释放,是解决死锁的一种方法
 * <p>
 * 
 * @author tianxingjian <h1>date: 2014-01-16</h1>
 */
public class SemaphoreDemo {
	private final Semaphore se;
	private int count;
	
	public SemaphoreDemo(int count){
		this.count = count;
		se = new Semaphore(count);
	} 
	
	public void doAction(){
		System.out.println(Thread.currentThread() + "[准备申请信号量!]");
		aquireAction();
		System.out.println(Thread.currentThread() + "[准备释放信号量!]");
		releaseAction();
	}
	
	public void aquireAction(){
		 try {  
             //acquire:获得;下面方法是获取信号量
             se.acquire();
             System.out.println(Thread.currentThread() + "[信号量申请成功,当前aquireAction()并发数为:" + (count - se.availablePermits()) + "]");
             Thread.sleep((long)Math.random()*10000);  
         } catch (InterruptedException e) {  
             e.printStackTrace();  
         }
	}
	
	public void releaseAction(){
		se.release();
		System.out.println(Thread.currentThread() + "[信号量释放成功!]");
	}
}

package cn.com.chp5.semaphore;

public class SemaphoreTest {
	
	public static void main(String[] args) {
		final SemaphoreDemo seDemo = new SemaphoreDemo(3);
		int threadCount = 10;
		String []threadName = new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K"};
		for(int i = 0; i < threadCount; i++){
			
			Thread th = new Thread(new Runnable() {	
				@Override
				public void run() {
					seDemo.doAction();
				}
			}, threadName[i]);
			th.start();
		}
	}

}


Barrier:

package cn.com.chp5.barrier;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

/**
 * <th>Barrier例子<th>
 * 
 * <p>
 * Barrier(障碍):Barrier等待一组活动都完成或者一组活动都开始后再执行线程的后续操作,如组织去公园,等人到齐了才出发
 * Barrier跟Latch区别: 1、Barrier的定义是所有线程都得到达同一点才能继续向下执行,Latch的定义是当Latch达到一个
 * 临界(终点)状态时所有的线程才能获得往下执行的通道。
 * 2、Latch是线程等待某个事件完成,Barrier是线程等待其他线程
 * 3、个人理解觉得Latch是被动等待,Barrier是主动等待。Barrier等待方会被等待方是同一属性级别,都是线程。如自发组织旅游,所有人按约定
 * 的时间,地点在同一个地方集合,先到的人等待其他人都到齐后再一起出发。Latch就像开会签到,开会前参与者先进行签到,当组织者等到所有参与者都签到
 * 后再进入会议主题
 * <p>
 * 
 * @author tianxingjian <h1>date: 2014-01-16</h1>
 */
public class BarrierDemo {
	private final CyclicBarrier barrier;
	
	public BarrierDemo(int barCount, Runnable runnable){
		barrier = new CyclicBarrier(barCount, runnable);
	}
	
	public void doAction(String [] thNames){
		for(int i = 0; i < thNames.length; i++){
			Thread th = new Thread(new BTRunnable(), thNames[i]);
			System.out.println("线程【" + thNames[i] + "】初始化完毕!");
			th.start();
		}
	}
	
	class BTRunnable implements Runnable{

		@Override
		public void run() {
			System.out.println(Thread.currentThread() + "[阻塞前操作!]" + System.currentTimeMillis());
			try {
				barrier.await();
				Thread.sleep((long) (Math.random() * 1000));
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (BrokenBarrierException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread() + "[阻塞后操作!]" + System.currentTimeMillis());
		}
		
	}
	
}



package cn.com.chp5.barrier;

/**
 * <th>Barrier例子<th>
 * 
 * <p>
	结果:改变BarrierDemo barrier = new BarrierDemo(5, new Runnable())中的参数5会发现“执行次数:”打印次数不一样,这是
	因为每有一组线程数量达到这个数时候就会往下执行,然后Barrier reset值,其他线程进入后重新组成一组线程通过这个Barrier。
	如果5改变为非thNames长度的因子,程序会阻塞,因为有最后一组线程数达不到这个值导致这些线程一直在等待状态
 * <p>
 * 
 * @author tianxingjian <h1>date: 2014-01-16</h1>
 */
public class BarrierTest {
	private static String []thNames = new String[]{"A", "B", "C", "D", "E", "F", "G", "H", "I", "J"}; 
	public static void main(String[] args) {

		BarrierDemo barrier = new BarrierDemo(5, new Runnable() {
			int count = 0;
			@Override
			public void run() {
				System.out.println("执行次数: " + ++count);
			}
		});
		
		barrier.doAction(thNames);
	}

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值