1.同步器Synchronizer
synchronizer是一个对象,它根据自身状态调节线程的控制流。阻塞队列可以扮演一个synchronizer,其他类型的synchronizer包括:信号量(semaphore)、关卡(barrier)和闭锁(latch)。
1.1闭锁(latch)
闭锁是可以延迟线程的进度直到线程到达终点状态的一种同步器。每个闭锁就相当于是一道大门,在闭锁到达重点状态之前,门一直是关闭的,没有线程可以通过,当到达终点状态时,门打开了,允许所有的线程通过。一旦闭锁到达终点状态,就不能再改变状态了,也就是永远保持开放的状态。闭锁用来确保特定活动直到其他活动都完成后才发生。

/**
* @Title: TestHarnessTest.java
* @Package synchronizer
* @Description: TODO
* @author 落叶飞翔的蜗牛
* @date 2017年12月16日 上午10:40:11
* @version V1.0
*/
package synchronizer;import java.util.concurrent.CountDownLatch;/*** @author 落叶飞翔的蜗牛* @date 2017年12月16日 上午10:40:11*/
public class TestHarness {public static long timeTasks(int nThread, final Runnable task) {long start = System.currentTimeMillis();final CountDownLatch startGate = new CountDownLatch(1);final CountDownLatch endGate = new CountDownLatch(nThread);for (int i = 0; i < nThread; i++) {Thread thread = new Thread() {@Overridepublic void run() {try {startGate.await();try {task.run();} finally {System.out.println("单个任务结束");endGate.countDown();}} catch (InterruptedException e) {e.printStackTrace();}}};thread.start();}startGate.countDown();try {endGate.await();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("所有任务结束");long end = System.currentTimeMillis();return end - start;}
}
/**
* @Title: TestHarnessTest.java
* @Package synchronizer
* @Description: TODO
* @author 落叶飞翔的蜗牛
* @date 2017年12月16日 上午10:46:05
* @version V1.0
*/
package synchronizer;import org.junit.Test;/*** @author 落叶飞翔的蜗牛* @date 2017年12月16日 上午10:46:05*/
public class TestHarnessTest {@Testpublic void test() {int nThread = 2;Runnable task = new Runnable() {@Overridepublic void run() {System.out.println("单个任务开始");try {Thread.sleep(1000*5);} catch (InterruptedException e) {e.printStackTrace();}}};long time = TestHarness.timeTasks(nThread, task);System.out.println("运行耗时:" + time);}
}

TestHarness使用两个阀门,开始阀门将计数器初始化为1,结束阀门将计数器初始化为工作线程的数量。每个工作线程要做的第一件事是等待阀门打开。每个线程最后一件事是将结束阀门减一,这样做使得工作线程有效的等待,直到最后一个工作线程完成了自己的任务,这个就可以计算整个过程的耗时。
1.2 FutureTask
FutureTask也可以作为闭锁。FutureTask描述了一个抽象的可携带结果的计算。FutureTask的计算是通过Callable实现的,它等价于一个可以携带结果的Runnable。它有三个状态:等待、运行和完成。完成包括:正常结束、取消和异常结束。一旦FutureTask进入完成状态,他就会永远停止在这个状态上。
Future.get的行为依赖于任务的状态。如果它已经完成,get立刻返回得到结果,否则会阻塞直到任务进入完成状态。FutureTask把计算的结果从当前的线程传送到需要该结果的线程。
利用FutureTask来完成异步任务,并在真正需要的计算结果之前就启动异步任务,这样可以减少等待的时间。

/**
* @Title: PreLoader.java
* @Package synchronizer.future
* @Description: TODO
* @author 落叶飞翔的蜗牛
* @date 2017年12月16日 下午2:24:46
* @version V1.0
*/
package synchronizer.future;import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;/*** @author 落叶飞翔的蜗牛* @date 2017年12月16日 下午2:24:46*/
public class PreLoader {/*** future:FutureTask<Object> TODO(模拟异步任务).* @author: 落叶飞翔的蜗牛* @date: 2017年12月16日 下午3:17:41*/private final FutureTask<Object> future = new FutureTask<>(new Callable<Object>() {/*** TODO 异步任务,睡眠5s* @see java.util.concurrent.Callable#call()*/@Overridepublic Object call() throws Exception {Thread.sleep(5000);return "SUCCESS";}});private final Thread thread = new Thread(future);public void start() {thread.start();}/*** get:(获取异步线程执行结果). <br/>* @author 落叶飞翔的蜗牛* @date:2017年12月16日 下午3:24:52* @return Object*/public Object get() {try {return future.get();} catch (InterruptedException | ExecutionException e) {// TODO Auto-generated catch blocke.printStackTrace();}return null;}
}
/**
* @Title: PreLoaderTest.java
* @Package synchronizer.future
* @Description: TODO(用一句话描述该文件做什么)
* @author 落叶飞翔的蜗牛
* @date 2017年12月16日 下午3:34:56
* @version V1.0
*/
package synchronizer.future;import org.junit.Test;/*** ClassName: PreLoaderTest <br/>* Function: 测试PreLoader. <br/>* date: 2017年12月16日 下午3:34:56 <br/>* @author 落叶飞翔的蜗牛* @version * @since JDK 1.6*/
public class PreLoaderTest {/*** test:(测试PreLoader). <br/>* @author 落叶飞翔的蜗牛* @date:2017年12月16日 下午3:47:29 */@Testpublic void test() {PreLoader preLoader = new PreLoader();preLoader.start();long start = System.currentTimeMillis();/*** 当程序需要用到异步数据时,可以调用get方法.* 如果异步任务完成,这直接返回.* 否则等待加载结束后返回*/System.out.println("获取结果:" + preLoader.get());long end = System.currentTimeMillis();System.out.println("执行耗时: " + (end - start));}
}

1.3 信号量(semaphore)
信号量用来控制能够同时访问某特定资源的活动的数量,或者是同时执行某一给定操作的数量。信号量可以用来实现资源池或者某一容器的限定的边界。
一个信号量管理一个有效的许可集合,活动能够获得许可,并在使用完后,释放许可。如果没可用的许可了,那么acquire方法会被阻塞,只有有可用的许可为止。Release方法向信号量返回一个许可。
信号量可以用来实现资源池,比如数据库连接池。每个池子有固定的长度,当池子为空,向池子申请资源将会失败,需要阻塞请求,一旦池子非空,解除阻塞。
用信号量将容器转化为有界容器。信号量被初始化为指定的大小,每次添加操作,向底层容器执行add操作之前,获取一个许可。同样的,每次删除的时候,在底层容器删除之后,释放一个许可。

/**
* @Title: BoundedHashSet.java
* @Package synchronizer.semaphore
* @Description: TODO(有界HashSet)
* @author 落叶飞翔的蜗牛
* @date 2017年12月16日 下午4:56:20
* @version V1.0
*/
package synchronizer.semaphore;import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Semaphore;/*** ClassName: BoundedHashSet <br/>* @author 落叶飞翔的蜗牛* date: 2017年12月16日 下午4:56:20 <br/>* Function: TODO 有界HashSet. <br/>* Reason: TODO ADD REASON(可选). <br/>* @version V1.0*/
public class BoundedHashSet<T> {private Set<T> set = null;private Semaphore semaphore = null;public BoundedHashSet(int bound) {this.set = Collections.synchronizedSet(new HashSet<>());semaphore = new Semaphore(bound);}/*** add:(添加元素). <br/>* TODO (添加元素之前,先获取一个许可,如果没有剩余许可,阻塞).<br/>* @author 落叶飞翔的蜗牛* @date: 2017年12月16日 下午5:11:14* @param t* @return* @throws InterruptedException */public boolean add(T t) throws InterruptedException {semaphore.acquire();boolean isAdded = false;try {isAdded = set.add(t);return isAdded;} finally {if(!isAdded) {semaphore.release();}}}/*** remove:(删除操作). <br/>* TODO (删除成功后释放许可).<br/>* @author 落叶飞翔的蜗牛* @date: 2017年12月16日 下午5:14:35* @param t* @return */public boolean remove(T t) {boolean isRemoved = set.remove(t);if(isRemoved) {semaphore.release();}return isRemoved;}
}
/**
* @Title: BoundedHashSetTest.java
* @Package synchronizer.semaphore
* @Description: 测试BoundedHashSet
* @author 落叶飞翔的蜗牛
* @date 2017年12月16日 下午5:18:12
* @version V1.0
*/
package synchronizer.semaphore;import org.junit.Test;/**
* @ClassName: BoundedHashSetTest
* @Description: (测试BoundedHashSet)
* @author 落叶飞翔的蜗牛
* @date 2017年12月16日 下午5:18:12
*/
public class BoundedHashSetTest {/*** testAdd:(测试添加). <br/>* @Description: (第四个元素加入失败).<br/>* @author 落叶飞翔的蜗牛* @date: 2017年12月16日 下午5:27:06* @throws InterruptedException */@Testpublic void testAdd() throws InterruptedException {BoundedHashSet<String> boundedHashSet = new BoundedHashSet<>(3);boundedHashSet.add("1");System.out.println("加入第1个元素成功");boundedHashSet.add("2");System.out.println("加入第2个元素成功");boundedHashSet.add("3");System.out.println("加入第3个元素成功");boundedHashSet.add("4");System.out.println("加入第4个元素成功");}/*** testAddAndRemove:(测试添加删除). <br/>* @Description: (删除元素1后,元素4就可以加入).<br/>* @author 落叶飞翔的蜗牛* @date: 2017年12月16日 下午5:29:45* @throws InterruptedException */@Testpublic void testAddAndRemove() throws InterruptedException {BoundedHashSet<String> boundedHashSet = new BoundedHashSet<>(3);boundedHashSet.add("1");System.out.println("加入第1个元素成功");boundedHashSet.add("2");System.out.println("加入第2个元素成功");boundedHashSet.add("3");System.out.println("加入第3个元素成功");boundedHashSet.remove("1");System.out.println("删除第1个元素成功");boundedHashSet.add("4");System.out.println("加入第4个元素成功");}
}

1.4 关卡(barrier)
关卡类似于闭锁,它能阻塞一组线程,知道某些事件的发生。关卡与闭锁的关键不同在于,所有的线程必须同时到达关卡点,才能继续处理。闭锁等待的是事件,关卡等待的是其他线程。就是说闭锁用来等待的事件就是countDown事件,只有该countDown事件执行后所有之前在等待的线程才有可能继续执行;而栅栏没有类似countDown事件控制线程的执行,只有线程的await方法能控制等待的线程执行。CyclicBarrier强调的是n个线程,大家相互等待,只要有一个没完成,所有人都得等着。
当线程到达关卡点,调用await,await会被阻塞,直到所有线程都到达关卡点。如果所偶线程都到达了关卡点,关卡被成功突破,这样所有的被阻塞的线程会被释放,此时关卡被重置,以备下一次使用。如果调用await超时,或者阻塞中的线程被中断,那么关卡就被置为失败。所有的对await未完成的调用,都会通过抛出BrokenBarrierException而终止。
10个人去春游,规定达到一个地点后才能继续前行:

/**
* @Title: CyclicBarrierWorker.java
* @Package synchronizer.barrier
* @Description: (用一句话描述该文件做什么)
* @Author 落叶飞翔的蜗牛
* @Date 2017年12月16日 下午6:19:50
* @Version V1.0
*/
package synchronizer.barrier;import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;/**
* @ClassName: CyclicBarrierWorker
* @Description: (这里用一句话描述这个类的作用)
* @Author 落叶飞翔的蜗牛
* @Date 2017年12月16日 下午6:19:50
*/
public class CyclicBarrierWorker implements Runnable {private int id;private CyclicBarrier barrier;public CyclicBarrierWorker(int id, final CyclicBarrier barrier) {this.id = id;this.barrier = barrier;}@Overridepublic void run() {// TODO Auto-generated method stubtry {System.out.println("第" + id + "个人到达,并等待");barrier.await(); // 大家等待最后一个线程到达} catch (InterruptedException | BrokenBarrierException e) {// TODO Auto-generated catch blocke.printStackTrace();}}
}
/**
* @Title: CyclicBarrierWorkerTest.java
* @Package synchronizer.barrier
* @Description: (测试类)
* @Author 落叶飞翔的蜗牛
* @Date 2017年12月16日 下午6:27:04
* @Version V1.0
*/
package synchronizer.barrier;import java.util.concurrent.CyclicBarrier;import org.junit.Test;/**
* @ClassName: CyclicBarrierWorkerTest
* @Description: (测试类)
* @Author 落叶飞翔的蜗牛
* @Date 2017年12月16日 下午6:27:04
*/
public class CyclicBarrierWorkerTest {@Testpublic void test() {int num = 10;CyclicBarrier barrier = new CyclicBarrier(num, new Runnable() {@Overridepublic void run() {//关卡通过后执行以下System.out.println("一起走啊!");}});for (int i = 1; i <= num; i++) {new Thread(new CyclicBarrierWorker(i, barrier)).start();}}
}

同步器Synchronizer相关推荐

  1. java j2se1.5_用J2SE1.5建立多任务的Java应用程序...

    J2SE 5.0中的java.util.concurrent程序包提供了一个新的线程框架组件,这个框架组件处理了与建立.执行和管理线程相关的很多低层细节信息.在本文中我们将细致地了解一下它的重要特性. ...

  2. wat java_并发工具优于wati、notify(69)

    现在几乎没有理由在使用wait 和 notify,使用高级工具代替 java.util.concurrent 包并发工具分三类: Executor 框架 并发集合(concurrent Collect ...

  3. java j2se1.5_Java教程 用J2SE1.5建立多任务的Java应用程序

    Future和FutureTask 在Java的早期版本中,查询运行中的线程状态,以及使线程在执行之后返回一个值是非常困难的.由于run(运行)方法返回void,你必须编写大量的代码从线程中返回一个值 ...

  4. java httpclient 异步请求_Java利用httpasyncclient进行异步HTTP请求

    Java利用httpasyncclient进行异步HTTP请求 前段时间有个需求在springmvc mapping的url跳转前完成一个统计的业务.显然需要进行异步的处理,不然出错或者异常会影响到后 ...

  5. 《Java并发编程实践》读书笔记

    http://macrochen.iteye.com/blog/660796 并发编程在编写高性能, 可伸缩应用的时候经常用到的一项技术, 也是相对来说比较高级的一项技术, 是每一个做后端开发的必备技 ...

  6. Redisson的使用与可重入锁

    目录 一.Redisson的使用 1.Redisson 2.导入依赖 3.建立Redssion配置类 4.使用 二.redisson的可重入锁 1.基本原理 2.test 3.图示 一.Redisso ...

  7. 读书笔记:Effective Java-第11章 并发Concurrency

    目录 Item 78: Synchronize access to shared mutable data Item 79: Avoid excessive synchronization Item ...

  8. 从HR系统到Windows AD域再到应用系统,如何自动化管理员工账号生命周期?

    随着企业的发展壮大,员工数量越来越多,业务系统数量也越来越多,同时伴随着员工入/离职.调岗等情况不断发生,企业 IT 运维承担着巨大的压力.主要体现在以下几个方面: IT 运维成本高 企业内部员工多. ...

  9. java经典问题总结

    一.考虑用静态工厂方法代替构造器: 构造器是创建一个对象实例最基本也最通用的方法,大部分开发者在使用某个class的时候,首先需要考虑的就是如何构造和初始化一个对象示例,而构造的方式首先考虑到的就是通 ...

最新文章

  1. 【微读书】《人工智能颠覆未来战争》连载之一:机器战胜人类?——AlphaGo人机对战的启示...
  2. 在字符串末尾添加字符使其成为回文串
  3. Android使用ConstraintLayout 加载RecyclerView数据显示不全
  4. 清华大学冯珺:基于强化学习的关系抽取和文本分类 | 实录·PhD Talk
  5. 网上教育能改变教育不公平的现状吗?
  6. winform checkbox要点击两次_这个Winform的UI库也太全了!四十多个控件都在这一个项目里了...
  7. AGG第四十四课 渲染问题:绘制较宽轮廓和尖锐边缘
  8. windows Hadoop环境搭建之一---软件准备
  9. 获取视图尺寸大小方法
  10. 创建触发器报错_Oracle行级触发器的使用
  11. 下载在线播放的电影,一个下载TS文件的工具,python小白。
  12. 红外图像是什么?红外线与计算机视觉相关的研究方向?(Visible and infrared image fusion)
  13. 阵列卡直通模式和raid模式_Dell R730服务器通过RAID在线扩容方法详解
  14. ps蒙版上渐变工具的使用及抠图方法
  15. 查看微信小程序的累计独立访客(UV)
  16. kgb压缩_KGB Archiver可能是可用的最佳压缩工具吗? 还是最慢?
  17. Android 华为手机获取相册图片路径,获取不到问题
  18. 应届生如何获取招聘信息
  19. 使用AirCrack破解wifi密码(wpa/wpa2)
  20. 如何解决DOSBox 0.74无法运行edit指令

热门文章

  1. SpringBoot 使用 Thymeleaf 如何发送带模板的Email邮件
  2. python将html转换成excel_Python将HTML格式文件中字段提取到EXCEL表的方法
  3. 1.第一节课,从头开始学C语言
  4. 【ASM】字节码操作 ClassWriter COMPUTE_FRAMES 的作用 与 visitMaxs 的关系
  5. 【OI做题记录】【BZOJ】【Usaco2008 Mar】土地购买
  6. .NET AutoCAD二次开发之路(二、直线篇)
  7. 岳飞诗词集萃[zz]
  8. 简述python文件操作的流程_Python文件操作详解
  9. 2021-05-30_蓝桥杯嵌入式拓展板STM32G431--光敏电阻
  10. python在数据分析方面的应用-数据分析应用方面Python和spss有什么区别?