[转载] java多线程学习-java.util.concurrent详解(二)Semaphore/FutureTask/Exchanger
转载自http://janeky.iteye.com/blog/770393
-----------------------------------------------------------------------------
3. Semaphore
我们先来学习一下JDK1.5 API中关于这个类的详细介绍:
“一个计数信号量。从概念上讲,信号量维护了一个许可集。如有必要,在许可可用前会阻塞每一个 acquire(),然后再获取该许可。每个 release() 添加一个许可,从而可能释放一个正在阻塞的获取者。但是,不使用实际的许可对象,Semaphore 只对可用许可的号码进行计数,并采取相应的行动。”
我们一般用它来控制某个对象的线程访问对象
例如,对于某个容器,我们规定,最多只能容纳n个线程同时操作
使用信号量来模拟实现
具体代码如下(参考 [JCIP])
- import java.util.Collections;
- import java.util.HashSet;
- import java.util.Set;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.Semaphore;
- public class TestSemaphore {
- public static void main(String[] args) {
- ExecutorService exec = Executors.newCachedThreadPool();
- TestSemaphore t = new TestSemaphore();
- final BoundedHashSet<String> set = t.getSet();
- for (int i = 0; i < 3; i++) {//三个线程同时操作add
- exec.execute(new Runnable() {
- public void run() {
- try {
- set.add(Thread.currentThread().getName());
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- });
- }
- for (int j = 0; j < 3; j++) {//三个线程同时操作remove
- exec.execute(new Runnable() {
- public void run() {
- set.remove(Thread.currentThread().getName());
- }
- });
- }
- exec.shutdown();
- }
- public BoundedHashSet<String> getSet() {
- return new BoundedHashSet<String>(2);//定义一个边界约束为2的线程
- }
- class BoundedHashSet<T> {
- private final Set<T> set;
- private final Semaphore semaphore;
- public BoundedHashSet(int bound) {
- this.set = Collections.synchronizedSet(new HashSet<T>());
- this.semaphore = new Semaphore(bound, true);
- }
- public void add(T o) throws InterruptedException {
- semaphore.acquire();//信号量控制可访问的线程数目
- set.add(o);
- System.out.printf("add:%s%n",o);
- }
- public void remove(T o) {
- if (set.remove(o))
- semaphore.release();//释放掉信号量
- System.out.printf("remove:%s%n",o);
- }
- }
- }
总结:Semaphore通常用于对象池的控制
4.FutureTask
我们先来学习一下JDK1.5 API中关于这个类的详细介绍:
“取消的异步计算。利用开始和取消计算的方法、查询计算是否完成的方法和获取计算结果的方法,此类提供了对 Future 的基本实现。仅在计算完成时才能获取结果;如果计算尚未完成,则阻塞 get 方法。一旦计算完成,就不能再重新开始或取消计算。
可使用 FutureTask 包装 Callable 或 Runnable 对象。因为 FutureTask 实现了 Runnable,所以可将 FutureTask 提交给 Executor 执行。
除了作为一个独立的类外,此类还提供了 protected 功能,这在创建自定义任务类时可能很有用。 “
应用举例:我们的算法中有一个很耗时的操作,在编程的是,我们希望将它独立成一个模块,调用的时候当做它是立刻返回的,并且可以随时取消的
具体代码如下(参考 [JCIP])
- import java.util.concurrent.Callable;
- import java.util.concurrent.ExecutionException;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.FutureTask;
- public class TestFutureTask {
- public static void main(String[] args) {
- ExecutorService exec=Executors.newCachedThreadPool();
- FutureTask<String> task=new FutureTask<String>(new Callable<String>(){//FutrueTask的构造参数是一个Callable接口
- @Override
- public String call() throws Exception {
- return Thread.currentThread().getName();//这里可以是一个异步操作
- }});
- try {
- exec.execute(task);//FutureTask实际上也是一个线程
- String result=task.get();//取得异步计算的结果,如果没有返回,就会一直阻塞等待
- System.out.printf("get:%s%n",result);
- } catch (InterruptedException e) {
- e.printStackTrace();
- } catch (ExecutionException e) {
- e.printStackTrace();
- }
- }
- }
总结:FutureTask其实就是新建了一个线程单独执行,使得线程有一个返回值,方便程序的编写
5. Exchanger
我们先来学习一下JDK1.5 API中关于这个类的详细介绍:
“可以在pair中对元素进行配对和交换的线程的同步点。每个线程将条目上的某个方法呈现给 exchange 方法,与伙伴线程进行匹配,并且在返回时接收其伙伴的对象。Exchanger 可能被视为 SynchronousQueue 的双向形式。Exchanger 可能在应用程序(比如遗传算法和管道设计)中很有用。 “
应用举例:有两个缓存区,两个线程分别向两个缓存区fill和take,当且仅当一个满了,两个缓存区交换
代码如下(参考了网上给的示例 http://hi.baidu.com/webidea/blog/item/2995e731e53ad5a55fdf0e7d.html)
- import java.util.ArrayList;
- import java.util.concurrent.Exchanger;
- public class TestExchanger {
- public static void main(String[] args) {
- final Exchanger<ArrayList<Integer>> exchanger = new Exchanger<ArrayList<Integer>>();
- final ArrayList<Integer> buff1 = new ArrayList<Integer>(10);
- final ArrayList<Integer> buff2 = new ArrayList<Integer>(10);
- new Thread(new Runnable() {
- @Override
- public void run() {
- ArrayList<Integer> buff = buff1;
- try {
- while (true) {
- if (buff.size() >= 10) {
- buff = exchanger.exchange(buff);//开始跟另外一个线程交互数据
- System.out.println("exchange buff1");
- buff.clear();
- }
- buff.add((int)(Math.random()*100));
- Thread.sleep((long)(Math.random()*1000));
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }).start();
- new Thread(new Runnable(){
- @Override
- public void run() {
- ArrayList<Integer> buff=buff2;
- while(true){
- try {
- for(Integer i:buff){
- System.out.println(i);
- }
- Thread.sleep(1000);
- buff=exchanger.exchange(buff);//开始跟另外一个线程交换数据
- System.out.println("exchange buff2");
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }}).start();
- }
- }
总结:Exchanger在特定的使用场景比较有用(两个伙伴线程之间的数据交互)
[转载] java多线程学习-java.util.concurrent详解(二)Semaphore/FutureTask/Exchanger的更多相关文章
- Android 布局学习之——Layout(布局)详解二(常见布局和布局参数)
[Android布局学习系列] 1.Android 布局学习之——Layout(布局)详解一 2.Android 布局学习之——Layout(布局)详解二(常见布局和布局参数) 3.And ...
- Shell学习之Bash变量详解(二)
Shell学习之Bash变量详解 目录 Bash变量 Bash变量注意点 用户自定义变量 环境变量 位置参数变量 预定义变量 Bash变量 用户自定义变量:在Bash中由用户定义的变量. 环境变量:这 ...
- [转载] java多线程学习-java.util.concurrent详解(一) Latch/Barrier
转载自http://janeky.iteye.com/blog/769965 Java1.5提供了一个非常高效实用的多线程包:java.util.concurrent, 提供了大量高级工具,可 ...
- [转载] java多线程学习-java.util.concurrent详解(四) BlockingQueue
转载自http://janeky.iteye.com/blog/770671 ------------------------------------------------------------- ...
- [转载] java多线程学习-java.util.concurrent详解(三)ScheduledThreadPoolExecutor
转载自http://janeky.iteye.com/blog/770441 ------------------------------------------------------------- ...
- java多线程学习--java.util.concurrent (转载)
题记:util和concurrent 包是后续重点先看的和学习的模块 原文地址:http://www.cnblogs.com/sunhan/p/3817806.html CountDownLatch, ...
- java多线程学习--java.util.concurrent
CountDownLatch,api 文档:http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.h ...
- java并发包java.util.concurrent详解
线程池ThreadPoolExecutor的使用 并发容器之CopyOnWriteArrayList 并发容器之CopyOnWriteArraySet 数据结构之ConcurrentHashMap,区 ...
- Java多线程Callable和Future类详解
public interface Callable<V> 返回结果并且可能抛出异常的任务.实现者定义了一个不带任何参数的叫做 call 的方法 public in ...
随机推荐
- C#仪器数据文件解析-Excel文件(xls、xlsx)
不少仪器工作站可以将数据导出为Excel文件,包括97-2003版本的xls文件和2007+的xlsx文件. 采集Excel文件相比采集pdf文件更容易.程序更健壮,毕竟Excel中数据有明确的行.列 ...
- Linux Redis集群搭建与集群客户端实现(Python)
硬件环境 本文适用的硬件环境如下 Linux版本:CentOS release 6.7 (Final) Redis版本: Redis已经成功安装,安装路径为/home/idata/yangfan/lo ...
- 干了这杯Java之LinkedList
LinkedList和ArrayList一样实现了List接口 ArrayList内部为数组 LinkedList内外为双向链表 实现了Deque接口,双端列队的实现 图片来自Wiki 内部实现为No ...
- Installation of the JDK-9 on ubuntu(linux上安装jdk-9)
Description:Java SE 9 is the latest update to the Java Platform(General Availability on 21 September ...
- 根据选中不同的图元来显示不同的属性面板changePropertyPane.html
在现实生活中,我们有很多时候需要根据选中不同的东西来获取不同的属性,并且就算是同类型的东西我们有时也希望显示不同的属性,就像每个人都有不同的个性,可能会有相同点,但是不可能完全相同. 根据这个思想,我 ...
- faster-rcnn中ROI_POOIING层的解读
在没有出现sppnet之前,RCNN使用corp和warp来对图片进行大小调整,这种操作会造成图片信息失真和信息丢失.sppnet这个模型推出来之后(关于这个网络的描述,可以看看之前写的一篇理解:ht ...
- java中集合类HashSet、ArrayList、LinkedList总结
[HashSet] 1. HashSet存储不能够存储相同的元素,元素是否相同的判断:重写元素的equals方法.equals方法和hashCode方法必须兼容,如:equals方法判断的是用户的名字 ...
- eclipse远程调试Linux环境下的web项目
前提: 远程服务器上的代码和本地的代码同步 第一步 : 配置远程服务器下的startup.sh文件 在第一行添加 : declare -x CATALINA_OPTS="-server -X ...
- 值得学习的C/C++开源框架(转)
值得学习的C语言开源项目 - 1. Webbench Webbench是一个在linux下使用的非常简单的网站压测工具.它使用fork()模拟多个客户端同时访问我们设定的URL,测试网站在压力下工作的 ...
- Vim 神器的打造方式
Vim 神器的打造方式 [字体:大 中 小] Vim 是一个上古神器,本篇文章主要持续总结使用 Vim 的过程中不得不了解的一些指令和注意事项,以及持续分享一个前端工作者不得不安装的一些插 ...