Java中的并发工具类
JDK的并发包,指的就是java.util.concurrent包下面的所有内容,一共有三个目录:
java.util.concurrent // 并发核心包
java.util.concurrent.atomic // 原子操作类包
java.util.concurrent.locks // 锁相关包
我们通常所说的Java并发编程的学习,其实指的就是这些相关类的学习。有时间的话,还是可以研读一下的。
OK,对JDK并发包有了大致了解以后,我们进入今天的正题:Java的并发工具类
这些工具类,都在java.util.concurrent并发核心包下,它们分别是:
一,CountDownLatch
CountDownLatch允许一个或者多个线程等待其他线程完成操作。比如我们需要处理多个TXT文件,然后统计每个TXT
文件的字数,这时我们可以用多个线程,每个线程处理一个TXT文件,等所有的文件都处理完成以后,最后打印出一个值,
这个值是所有文件中的字数的总和。
首先我们看一下java.util.concurrent.CountDownLatch.class的实现:
1,使用FORK/JOIN框架来处理这个应用场景
join()方法的实现代码如下:join方法用来让当前执行的线程,等待join线程执行结束
2,使用CountDownLatch工具类来处理这个应用场景
二,CyclicBarrier
CyclicBarrier的功能和CountDownLatch类似,它是一个可循环的屏障,作用就是让一组线程到达一个屏障(
也叫同步点)时被阻塞,然后等待其他线程,直到所有的线程都到达屏障时,屏障才会开门,所有线程才会继续
执行。CyclicBarrier默认的构造方法是CyclicBarrier(int parties),参数parties表示屏障拦截的线程的数量,
当一个线程A到达屏障时,通过调用await方法,告知CyclicBarrier已经到达屏障,然后线程A被阻塞。
控制台输出:
三,Semaphore
Semaphore(信号量)是用来控制同时访问特定资源的线程数量的,它通过协调各个线程,以保证合理的
使用公共资源。信号量通常都是用来做资源访问的控制,比如数据库连接的控制。现在有这样一个应用场景,
我们需要启动20个线程,并发的读取1000个excel文档,但是读到内存后,还需要存入数据库中,而数据库连接
池的最大连接数是5,这时,我们就要用信号量来进行连接控制。
四,Exchanger
Exchanger(交换者)是一个用于线程间协作的工具类。Exchanger用于进行线程间的数据交换。它提供一个同步点,在这个同步点,
2个线程可以交换彼此的数据。如果一个线程先执行exchange()方法,它会一直等待第二个线程执行exchange()方法,当2个线程都到达同
步点以后,这2个线程就可以交换数据了,将A线程产生的数据传递给B线程。
Exchanger通常用于遗传算法,遗传算法里,需要选出2个人作为交配对象,这时会交换2个人的数据,并使用交叉规则得出2个交配结果。
Exchanger也可以用于校对工作,比如我们需要将纸质的银行流水通过人工的方式录入成电子银行流水,为了避免错误,采用AB岗2人进行录入,
录入到excel之后,系统需要加载这2个excel,并对这2个excel数据进行校对,看看是否录入一致。
JDK的并发包,指的就是java.util.concurrent包下面的所有内容,一共有三个目录:
java.util.concurrent // 并发核心包
java.util.concurrent.atomic // 原子操作类包
java.util.concurrent.locks // 锁相关包
我们通常所说的Java并发编程的学习,其实指的就是这些相关类的学习。有时间的话,还是可以研读一下的。
下面列举一下这些包下面的所有的java类,我使用的JDK版本是1.6,不同版本可能会有所不同。大部分应该都是一样的,仅供参考。
java.util.concurrent // 并发核心包
java.util.concurrent.AbstractExecutorService.class
java.util.concurrent.ArrayBlockingQueue.class
java.util.concurrent.BlockingDeque.class
java.util.concurrent.BlockingQueue.class
java.util.concurrent.BrokenBarrierException.class
java.util.concurrent.Callable.class
java.util.concurrent.CancellationException.class
java.util.concurrent.CompletionService.class
java.util.concurrent.ConcurrentHashMap.class
java.util.concurrent.ConcurrentLinkedQueue.class
java.util.concurrent.ConcurrentMap.class
java.util.concurrent.ConcurrentNavigableMap.class
java.util.concurrent.ConcurrentSkipListMap.class
java.util.concurrent.ConcurrentSkipListSet.class
java.util.concurrent.CopyOnWriteArrayList.class
java.util.concurrent.CopyOnWriteArraySet.class
java.util.concurrent.CountDownLatch.class
java.util.concurrent.CyclicBarrier.class
java.util.concurrent.Delayed.class
java.util.concurrent.DelayQueue.class
java.util.concurrent.Exchanger.class
java.util.concurrent.ExecutionException.class
java.util.concurrent.Executor.class
java.util.concurrent.ExecutorCompletionService.class
java.util.concurrent.Executors.class
java.util.concurrent.ExecutorService.class
java.util.concurrent.Future.class
java.util.concurrent.FutureTask.class
java.util.concurrent.LinkedBlockingDeque.class
java.util.concurrent.LinkedBlockingQueue.class
java.util.concurrent.PriorityBlockingQueue.class
java.util.concurrent.RejectedExecutionException.class
java.util.concurrent.RejectedExecutionHandler.class
java.util.concurrent.RunnableFuture.class
java.util.concurrent.RunnableScheduledFuture.class
java.util.concurrent.ScheduledExecutorService.class
java.util.concurrent.ScheduledFuture.class
java.util.concurrent.ScheduledThreadPoolExecutor.class
java.util.concurrent.Semaphore.class
java.util.concurrent.SynchronousQueue.class
java.util.concurrent.ThreadFactory.class
java.util.concurrent.ThreadPoolExecutor.class
java.util.concurrent.TimeoutException.class
java.util.concurrent.TimeUnit.class
java.util.concurrent.atomic // 原子操作类包
java.util.concurrent.atomic.AtomicBoolean.class
java.util.concurrent.atomic.AtomicInteger.class
java.util.concurrent.atomic.AtomicIntegerArray.class
java.util.concurrent.atomic.AtomicIntegerFieldUpdater.class
java.util.concurrent.atomic.AtomicLong.class
java.util.concurrent.atomic.AtomicLongArray.class
java.util.concurrent.atomic.AtomicLongFieldUpdater.class
java.util.concurrent.atomic.AtomicMarkableReference.class
java.util.concurrent.atomic.AtomicReference.class
java.util.concurrent.atomic.AtomicReferenceArray.class
java.util.concurrent.atomic.AtomicReferenceFieldUpdater.class
java.util.concurrent.atomic.AtomicStampedReference.class
java.util.concurrent.locks // 锁相关包
java.util.concurrent.locks.AbstractOwnableSynchronizer.class
java.util.concurrent.locks.AbstractQueuedLongSynchronizer.class
java.util.concurrent.locks.AbstractQueuedSynchronizer.class
java.util.concurrent.locks.Condition.class
java.util.concurrent.locks.Lock.class
java.util.concurrent.locks.LockSupport.class
java.util.concurrent.locks.ReadWriteLock.class
java.util.concurrent.locks.ReentrantLock.class
java.util.concurrent.locks.ReentrantReadWriteLock.class
OK,对JDK并发包有了大致了解以后,我们进入今天的正题:Java的并发工具类
这些工具类,都在java.util.concurrent并发核心包下,它们分别是:
java.util.concurrent.CountDownLatch.class
java.util.concurrent.CyclicBarrier.class
java.util.concurrent.Semaphore.class
java.util.concurrent.Exchanger.class
一,CountDownLatch
CountDownLatch允许一个或者多个线程等待其他线程完成操作。比如我们需要处理多个TXT文件,然后统计每个TXT
文件的字数,这时我们可以用多个线程,每个线程处理一个TXT文件,等所有的文件都处理完成以后,最后打印出一个值,
这个值是所有文件中的字数的总和。
首先我们看一下java.util.concurrent.CountDownLatch.class的实现:
public class CountDownLatch {
// 使用队列同步器(内部类)
private static final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 4982264981922014374L;
Sync(int count) {
setState(count);
}
int getCount() {
return getState();
}
public int tryAcquireShared(int acquires) {
return getState() == 0? 1 : -1;
}
public boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
}
// 创建队列同步器对象sync
private final Sync sync;
// 带参数构造方法
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
// 等待
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
// 超时等待
public boolean await(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
public void countDown() {
sync.releaseShared(1);
}
public long getCount() {
return sync.getCount();
}
public String toString() {
return super.toString() + "[Count = " + sync.getCount() + "]";
}
}
1,使用FORK/JOIN框架来处理这个应用场景
join()方法的实现代码如下:join方法用来让当前执行的线程,等待join线程执行结束
public final synchronized void join(long millis) throws InterruptedException {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
wait(0);
}
}
else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
package com.synchronizedLearning.util;
import java.util.logging.Logger;
/**
*
* @author yangcq
* @description CountDownLatch工具类的使用
*
*/
public class ByForkJoin {
static Logger logger = Logger.getAnonymousLogger();
public static void main(String[] args) {
// 线程1
Thread thread1 = new Thread(
new Runnable(){
@Override
public void run(){
logger.info("线程" + Thread.currentThread().getName() + "执行完了...");
}
}
);
// 线程2
Thread thread2 = new Thread(
new Runnable(){
@Override
public void run(){
logger.info("线程" + Thread.currentThread().getName() + "执行完了...");
}
}
);
thread1.start();
thread2.start();
try {
logger.info("当前活跃的线程数:" + Thread.activeCount());
thread1.join();
logger.info("当前活跃的线程数:" + Thread.activeCount());
thread2.join();
logger.info("当前活跃的线程数:" + Thread.activeCount());
logger.info("所有的线程都执行完了...");
}
catch (InterruptedException e) {
e.printStackTrace();
logger.info("线程执行过程中出错了...");
}
finally{
logger.info("当前活跃的线程数:" + Thread.activeCount());
logger.info("当前活跃的线程是:" + Thread.currentThread().getName());
}
}
}
控制台输出:
2016-7-31 10:26:55 com.synchronizedLearning.util.ByForkJoin main
信息: 当前活跃的线程数:3
2016-7-31 10:26:55 com.synchronizedLearning.util.ByForkJoin$1 run
信息: 线程Thread-1执行完了...
2016-7-31 10:26:55 com.synchronizedLearning.util.ByForkJoin$2 run
信息: 线程Thread-2执行完了...
2016-7-31 10:26:55 com.synchronizedLearning.util.ByForkJoin main
信息: 当前活跃的线程数:1
2016-7-31 10:26:55 com.synchronizedLearning.util.ByForkJoin main
信息: 当前活跃的线程数:1
2016-7-31 10:26:55 com.synchronizedLearning.util.ByForkJoin main
信息: 所有的线程都执行完了...
2016-7-31 10:26:55 com.synchronizedLearning.util.ByForkJoin main
信息: 当前活跃的线程数:1
2016-7-31 10:26:55 com.synchronizedLearning.util.ByForkJoin main
信息: 当前活跃的线程是:main
2,使用CountDownLatch工具类来处理这个应用场景
package com.synchronizedLearning.util;
import java.util.concurrent.CountDownLatch;
import java.util.logging.Logger;
/**
*
* @author yangcq
* @description CountDownLatch工具类的使用
*
*/
public class CountDownLatchUtilLearning {
static Logger logger = Logger.getAnonymousLogger();
static // 创建CountDownLatch对象
CountDownLatch countDownLatch = new CountDownLatch(2);
public static void main(String[] args){
new Thread(
new Runnable(){
@Override
public void run(){
logger.info("1");
countDownLatch.countDown();
logger.info("2");
countDownLatch.countDown();
}
}
).start();
try {
countDownLatch.await();
logger.info("3");
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
二,CyclicBarrier
CyclicBarrier的功能和CountDownLatch类似,它是一个可循环的屏障,作用就是让一组线程到达一个屏障(
也叫同步点)时被阻塞,然后等待其他线程,直到所有的线程都到达屏障时,屏障才会开门,所有线程才会继续
执行。CyclicBarrier默认的构造方法是CyclicBarrier(int parties),参数parties表示屏障拦截的线程的数量,
当一个线程A到达屏障时,通过调用await方法,告知CyclicBarrier已经到达屏障,然后线程A被阻塞。
package com.synchronizedLearning.util;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.logging.Logger;
/**
*
* @author yangcq
* @description CyclicBarrier工具类的使用
*
*/
public class CyclicBarrierLearning {
static Logger logger = Logger.getAnonymousLogger();
// 创建CyclicBarrier对象
static CyclicBarrier countDownLatch = new CyclicBarrier(2);
public static void main(String[] args) {
// 子线程
new Thread(
new Runnable(){
@Override
public void run(){
try {
countDownLatch.await(); // 等待,直到所有线程执行完成
}
catch (InterruptedException e) {
e.printStackTrace();
}
catch (BrokenBarrierException e) {
e.printStackTrace();
}
finally{
logger.info("线程" + Thread.currentThread().getName() + "执行完了...");
}
}
}
).start();
// 主线程
try{
countDownLatch.await(); // 等待,直到所有线程执行完成
}
catch(Exception e){
logger.info("异常...");
}
finally{
logger.info("线程" + Thread.currentThread().getName() + "执行完了...");
}
}
}
控制台输出:
2016-7-31 13:16:27 com.synchronizedLearning.util.CyclicBarrierLearning main
信息: 线程main执行完了...
2016-7-31 13:16:27 com.synchronizedLearning.util.CyclicBarrierLearning$1 run
信息: 线程Thread-1执行完了...
三,Semaphore
Semaphore(信号量)是用来控制同时访问特定资源的线程数量的,它通过协调各个线程,以保证合理的
使用公共资源。信号量通常都是用来做资源访问的控制,比如数据库连接的控制。现在有这样一个应用场景,
我们需要启动20个线程,并发的读取1000个excel文档,但是读到内存后,还需要存入数据库中,而数据库连接
池的最大连接数是5,这时,我们就要用信号量来进行连接控制。
package com.synchronizedLearning.util;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.logging.Logger;
/**
*
* @author yangcq
* @description Semaphore工具类的使用
*
*/
public class SemaphoreLearning {
static Logger logger = Logger.getAnonymousLogger();
private static final int TOTAL_THREAD = 20; // 启动的总线程数
private static final int MAX_CONNECTION_THREAD = 5; // 同时获得的最大连接数量
private static ExecutorService threadPool = Executors.newFixedThreadPool(TOTAL_THREAD);
private static Semaphore semaphore = new Semaphore(MAX_CONNECTION_THREAD);
public static void main(String[] args) {
for(int i=0;i<TOTAL_THREAD;i++){
threadPool.execute(
new Runnable(){
@Override
public void run(){
try{
semaphore.acquire();
logger.info("保存数据到数据库...");
semaphore.release();
}
catch(InterruptedException e){
}
finally{
}
}
}
);
}
threadPool.shutdown();
}
}
四,Exchanger
Exchanger(交换者)是一个用于线程间协作的工具类。Exchanger用于进行线程间的数据交换。它提供一个同步点,在这个同步点,
2个线程可以交换彼此的数据。如果一个线程先执行exchange()方法,它会一直等待第二个线程执行exchange()方法,当2个线程都到达同
步点以后,这2个线程就可以交换数据了,将A线程产生的数据传递给B线程。
Exchanger通常用于遗传算法,遗传算法里,需要选出2个人作为交配对象,这时会交换2个人的数据,并使用交叉规则得出2个交配结果。
Exchanger也可以用于校对工作,比如我们需要将纸质的银行流水通过人工的方式录入成电子银行流水,为了避免错误,采用AB岗2人进行录入,
录入到excel之后,系统需要加载这2个excel,并对这2个excel数据进行校对,看看是否录入一致。
package com.yangcq.learning;
import java.util.concurrent.Exchanger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
*
* @author yangcq
* @description Java并发工具类 Exchanger
*
*/
public class ExchangerLearning {
static final Log log = LogFactory.getLog(ExchangerLearning.class);
// 创建exchanger对象
private static final Exchanger<String> exchanger = new Exchanger<String>();
// 创建线程池
private static ExecutorService threadPool = Executors.newFixedThreadPool(2);
//
public static void main(String[] args) {
// 线程A,录入银行流水A
threadPool.execute(
new Runnable(){
@Override
public void run(){
try{
String transflow_A = "银行流水A";
exchanger.exchange(transflow_A);
log.info("transflow_A 录入成功...");
}
catch(InterruptedException e){
log.info("执行线程抛出了异常...");
}
finally{
}
}
}
);
// 线程B,录入银行流水B
threadPool.execute(
new Runnable(){
@Override
public void run(){
try{
String transflow_B = "银行流水B"; // 如果2个线程中有一个没有执行exchange()方法,则会一直等待。
String transflow_A = exchanger.exchange(transflow_B);
log.info("判断A数据和B数据是否一致:" + transflow_A.equals(transflow_B));
log.info("A录入的数据是:" + transflow_A);
log.info("B录入的数据是:" + transflow_B);
}
catch(InterruptedException e){
log.info("执行线程抛出了异常...");
}
finally{
}
}
}
);
// 关闭线程池
threadPool.shutdown();
}
}
控制台输出:
2016-8-1 8:29:06 com.yangcq.learning.ExchangerLearning$2 run
信息: 判断A数据和B数据是否一致:false
2016-8-1 8:29:06 com.yangcq.learning.ExchangerLearning$1 run
信息: transflow_A 录入成功...
2016-8-1 8:29:07 com.yangcq.learning.ExchangerLearning$2 run
信息: A录入的数据是:银行流水A
2016-8-1 8:29:07 com.yangcq.learning.ExchangerLearning$2 run
信息: B录入的数据是:银行流水B