并发包下一些并发类
引言:JDK1.5的并发包不仅仅提供了前文所说的线程池框架,还提供了一系列并发类,来便于我们编写高并发代码,本文我们来一一介绍。
一、CountDownLatch类
代码如下:
package com.example.first;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class UseCountDown {
public static void main(String args[]) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(2);
Runnable runnable1 = new Runnable() {
@Override
public void run() {
System.out.println("线程1来了,await阻塞");
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("阻塞结束,开始执行");
}
};
Runnable runnable2 = new Runnable() {
@Override
public void run() {
System.out.println("线程2来了");
countDownLatch.countDown();
}
};
Runnable runnable3 = new Runnable() {
@Override
public void run() {
System.out.println("线程3来了");
countDownLatch.countDown();
}
};
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
fixedThreadPool.execute(runnable1);
fixedThreadPool.execute(runnable2);
fixedThreadPool.execute(runnable3);
fixedThreadPool.shutdown();
}
}
功能主要是提供了两个方法,一个是await(),用于阻塞当前线程,一个是countDown方法,用于改变CountDownLatch对象的状态。
在CountDownLatch对象初始化的时候,需要在构造函数下加上一个整形的变量i,而await方法就会阻塞线程,只有当其他线程,执行了i次countDown方法,才能将被await阻塞的方法给重新激活。
使用方式是十分的简单,使用场景主要在监听其他线程的初始化操作,当初始化完毕之后,便会提醒主线程开始运行。
二、CyclicBarrier类
代码如下:
package com.example.first;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class UseBarrier {
public static void main(String args[]) throws InterruptedException {
// CountDownLatch countDownLatch = new CountDownLatch(2);
CyclicBarrier cyclicBarrier = new CyclicBarrier(4);
Runnable runnable1 = new Runnable() {
@Override
public void run() {
System.out.println("线程1准备好了");
try {
cyclicBarrier.await();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("阻塞结束,线程1开始执行");
}
};
Runnable runnable2 = new Runnable() {
@Override
public void run() {
System.out.println("线程2准备好了");
try {
cyclicBarrier.await();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("阻塞结束,线程2开始执行");
}
};
Runnable runnable3 = new Runnable() {
@Override
public void run() {
System.out.println("线程3准备好了");
try {
cyclicBarrier.await();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("阻塞结束,线程3开始执行");
}
};
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
fixedThreadPool.execute(runnable1);
fixedThreadPool.execute(runnable2);
fixedThreadPool.execute(runnable3);
fixedThreadPool.shutdown();
}
}
特地去查了一下Barrier是什么意思,大概意思就是栅栏的意思,十分形象。实例化的方式和CountDown很像,都是有一个整数为参数的构造函数,也提供了await方法用于阻塞当前线程,激活线程的时机是当await的数量到达了构造参数中整数的值时。
十分贴切他的意思--栅栏,只有当线程都到齐了,才能各就各位起跑。
三、Future和FutureTask类
代码如下:
package com.example;
import java.util.concurrent.*;
public class UseFuture {
public static void main(String args[]) throws Exception {
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(3000);
return "future开始!";
}
};
FutureTask<String> futureTask = new FutureTask<String>(callable);
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
fixedThreadPool.submit(futureTask);
System.out.println(futureTask.get());
fixedThreadPool.shutdown();
}
}
实现方式,在很早之前写过,但是忘了大概。核心就是要使用Callable接口,重写里面的call方法,call方法有返回值,返回类型为Callable的泛型对象,将Callable出来的对象传入FutureTask的构造方法,再将FutureTask对象传给线程池的submit方法。
submit和execute在大多数情况下无异,但是submit能够传入callable参数,返回Future参数,值得一说的是,FutureTask实现了Callable接口和Future。最后,当主线程调用了FutureTask的get()方法,便会等待FutureTask任务线程执行,返回call方法的值。这是JDK对Future模式的一种实现。