`
janeky
  • 浏览: 366539 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

java多线程学习-java.util.concurrent详解(二)Semaphore/FutureTask/Exchanger

阅读更多
前一篇文章 http://janeky.iteye.com/category/124727
我们学习了java.util.concurrent的CountDownLatch和CyclicBarrier
今天我们继续共同来探讨其他的多线程组件
-----------------------------------------------------------------------------
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多线程资料,欢迎访问 http://janeky.iteye.com/category/124727
6
2
分享到:
评论
3 楼 allstar2012 2013-06-18  
xhfei 写道

运行一下Semaphore的程序,发现不能够正常运行,问题出在remove方法时候是remove的是Thread.currentThread().getName(),和add进去的值不一样,导致semaphore.release();不能释放掉信号量。在add和remove的地方需要修改一下,以保证能够正常remove。

确实是这样,楼主的例子我是一个一个过的。
现在有些地方还是看的云里雾里的。
2 楼 muyoufang001 2012-10-19  
发现了,没有修改
1 楼 xhfei 2010-12-20  

运行一下Semaphore的程序,发现不能够正常运行,问题出在remove方法时候是remove的是Thread.currentThread().getName(),和add进去的值不一样,导致semaphore.release();不能释放掉信号量。在add和remove的地方需要修改一下,以保证能够正常remove。

相关推荐

    java多线程学习-java.util.concurrent详解(一) Latch/Barrier

    `java.util.concurrent`包是Java提供的一个强大的多线程工具库,其中包含了许多类和接口,如`CountDownLatch`和`CyclicBarrier`,它们为程序员提供了更高级别的同步和协调机制。这篇文档将详细解析这两个工具类的...

    java并发工具包 java.util.concurrent中文版用户指南pdf

    1. java.util.concurrent - Java 并发工具包 2. 阻塞队列 BlockingQueue 3. 数组阻塞队列 ArrayBlockingQueue 4. 延迟队列 DelayQueue 5. 链阻塞队列 LinkedBlockingQueue 6. 具有优先级的阻塞队列 ...

    atlassian-util-concurrent-0.0.12.jar.zip

    本文将详细探讨Atlassian发布的`atlassian-util-concurrent-0.0.12.jar`库,这是一个专门针对并发处理的工具集,旨在简化Java开发中的多线程操作。 `atlassian-util-concurrent-0.0.12.jar.zip`是这个库的压缩文件...

    backport-util-concurrent(2.2 /3.1)

    总的来说,backport-util-concurrent库是Java并发编程的重要补充,它使得开发者能够利用先进的并发工具,即使在较低版本的Java环境中也能实现高效的多线程应用。无论是ReentrantLock的细粒度控制,还是Phaser的灵活...

    backport-util-concurrent.jar

    backport-util-concurrent.jarbackport-util-concurrent.jarbackport-util-concurrent.jar

    backport-util-concurrent-3.1.jar geronimo-stax-api_1.0_spec-1.0.1.jar 下载

    backport-util-concurrent-3.1.jar 和 geronimo-stax-api_1.0_spec-1.0.1.jar 复制到 MyEclipse 6.5\eclipse\plugins\Axis2_Codegen_Wizard_1.3.0\lib 文件夹下。 (3).注册此 jar 包: 修改MyEclipse 6.5\eclipse...

    Tomcat内存溢出的解决方法(java.util.concurrent.ExecutionException)

    "java.util.concurrent.ExecutionException: java.lang.OutOfMemoryError" 是一个典型的错误提示,它表明在并发执行过程中遇到了内存不足的问题。下面我们将深入探讨这个问题的原因、影响以及如何解决。 内存溢出...

    Java并发工具包java.util.concurrent用户指南中英文对照阅读版.pdf

    java.util.concurrent - Java 并发工具包 2. 阻塞队列 BlockingQueue 3. 数组阻塞队列 ArrayBlockingQueue 4. 延迟队列 DelayQueue 5. 链阻塞队列 LinkedBlockingQueue 6. 具有优先级的阻塞队列 ...

    java.util.concurrent-多线程框架.docx

    java.util.concurrent 多线程框架 java.util.concurrent 多线程框架是 Java 语言中用于多线程编程的库。该库提供了多种线程池实现、并发集合、同步器、lock 等多种机制,以便开发者更方便地编写高效、可靠的多线程...

    backport-util-concurrent-java12-3.1-sources.jar

    官方版本,亲测可用

    backport-util-concurrent-3.1.jar

    - copy %AXIS2_HOME%\lib\backport-util-concurrent-3.1.jar 到%ECLIPSE_HOME%\plugins\Axis2_Codegen_Wizard_1.3.0\lib - 注册此 jar 包: 編輯 %ECLIPSE_HOME%\plugins\Axis2_Codegen_Wizard_1.3.0\plugin.xml , ...

    java并发工具包 java.util.concurrent中文版pdf

    ### Java并发工具包 `java.util.concurrent` 知识点详解 #### 一、引言 随着多核处理器的普及和应用程序复杂度的增加,多线程编程成为了现代软件开发不可或缺的一部分。为了简化并发编程的复杂性,Java 5 引入了 `...

    JDK研究系列--》util.concurrent(java.util part3)

    合适研究底层研发员,但,一般程序员也必须掌握的要点 JDK研究系列--》util.concurrent(java.util part3)

    jdk-6u45-linux-x64.bin

    5. **并发工具类库**:Java并发工具包(java.util.concurrent)在1.6版本中得到加强,增加了如`CountDownLatch`、`CyclicBarrier`、`Semaphore`等同步工具,便于多线程编程。 6. **XPath和XML处理**:JDK 1.6改进了...

    jdk-8u251-linux-x64.tar.gz

    Java Development Kit(JDK)是Java编程语言的核心组件,它包含了一组开发工具,用于创建、编译、调试和运行Java应用程序。在这个场景中,我们关注的是`jdk-8u251-linux-x64.tar.gz`,这是一个针对Linux操作系统的64...

    jdk-8u201-linux-x64.tar.gz jdk8版本下载

    Java Development Kit(简称JDK)是Oracle公司发布的用于开发和运行Java应用程序的工具包,它包含Java编译器、Java虚拟机(JVM)以及Java类库等组件。本篇将详细探讨 JDK 8u201 版本在Linux环境下的安装与使用。 ...

    Java高性能线程库(java.util.concurrent包的补充)

    一个高性能的Java线程库,该库是 JDK 1.5 中的 java.util.concurrent 包的补充,可用于基于并发消息机制的应用。该类库不提供远程的消息功能,其设计的宗旨是实现一个内存中的消息传递机制. 主要特点有: * All ...

    【IT十八掌徐培成】Java基础第21天-04.URL-多线程下载-暂停操作.zip

    在Java中,可以使用`java.lang.Thread`类或者`java.util.concurrent`包下的`ExecutorService`、`ThreadPoolExecutor`等工具来创建和管理线程。通过将大文件分割成多个部分,每个部分在一个独立的线程中进行下载,...

Global site tag (gtag.js) - Google Analytics