1.Fork/Join
- 分而治之
- 工作密取
A线程比B线程先运行完,则从B工作队列的最后取一个任务交给A(A帮B的忙)
多线程开发核心:快+资源不能争抢+充分利用资源(尽量让CPU全部跑起来)
- 使用流程
- ForkJoinTask
--方法------------------------------------
1.fork():将某子任务发生给ForkJoin执行器
相当于invokeAll(task1,task2...)
2.join():等待某子任务执行结束并返回结果(工作密取)
--子类------------------------------------
1.RecursiveTask:有返回
2.RecursiveActive:无返回
3.CountedCompleter
public class ForkJoin_FindDirsFiles extends RecursiveAction {
private File path;
public ForkJoin_FindDirsFiles(File path) {this.path = path;}
@Override
protected void compute() {
List<ForkJoin_FindDirsFiles> subTasks = new ArrayList<>();
File[] files = path.listFiles();
if (files != null) {
for (File file : files) {
if (file.isDirectory()) {
ForkJoin_FindDirsFiles sonTask = new ForkJoin_FindDirsFiles(file);
subTasks.add(sonTask);
} else {
if (file.getAbsolutePath().endsWith("txt")) {
System.out.println("文件:" + file.getAbsolutePath());
}
}
}
if (!subTasks.isEmpty()) {
for (ForkJoin_FindDirsFiles subTask : invokeAll(subTasks)) {
subTask.join();
}
}
}
}
public static void main(String[] args) {
long start = System.currentTimeMillis();
try {
ForkJoinPool pool = new ForkJoinPool();
ForkJoin_FindDirsFiles task = new ForkJoin_FindDirsFiles(new File("c:/"));
pool.invoke(task);
System.out.println("任务运行中");
Thread.sleep(1);
int otherWork = 0;
for (int i = 0; i < 100; i++) {
otherWork = otherWork + 1;
}
System.out.println("主线程在完成其他工作,此工作结束" + otherWork);
task.join();
System.out.println("任务结束");
System.out.println("耗时:" + (System.currentTimeMillis() - start));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
2.CountDownLatch
一组线程等待其他线程工作完后再运行(加强版join)
解决join中无法知道让行线程合适运行完的问题
await():等待
countDown():计数器减1,减到0线程开始运行
CountDownLatch(初始值):计数器countDown的初值
public class CountDownLatch1 {
public static void main(String[] args) throws InterruptedException {
final CountDownLatch countDownLatch = new CountDownLatch(1);
for (int i = 1; i <= 5; i++) {
new Thread(() -> {
try {
String name = "[" + Thread.currentThread().getName() + "]";
System.out.println(name + "阻塞");
countDownLatch.await();
String str = "[" + Thread.currentThread().getName() + "]";
System.out.println(str + "开始执行");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
Thread.sleep(2000);
System.out.println("主线程在运行");
countDownLatch.countDown();
}
}
3.CyclicBarrier
一组线程达到某屏障,直到组内最后一个线程到达屏障时,屏障放开,所有阻塞的线程全部继续运行
CyclicBarrier(参与者数量):参与的线程都阻塞,直到阻塞的线程数等于参与线程数时,全部阻塞线程继续运行
CyclicBarrier(参与者数量,Runnable):屏障放开,参数2定义的任务被执行一次
await():当等待者数量到达参与者数量就同时解除屏障
public class UseCyclicBarrier {
private static CyclicBarrier barrier = new CyclicBarrier(5, new CollectThread());
public static void main(String[] args) {
for (int i = 0; i <= 4; i++) {
Thread thread = new Thread(new SubThread());
thread.start();
}
}
private static class CollectThread implements Runnable {
@Override
public void run() {
System.out.println("执行醒来后的另一个处理");
}
}
private static class SubThread implements Runnable {
@Override
public void run() {
Random rd = new Random();
try {
if (rd.nextBoolean()) {
Thread.sleep(2000 + Thread.currentThread().getId());
System.out.println("Thread_" + Thread.currentThread().getId() + "睡眠两秒后开始");
}
System.out.println(Thread.currentThread().getId() + "开始等待");
barrier.await();
System.out.println("屏障打开,当前Thread_" + Thread.currentThread().getId() + "完成其他业务逻辑");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
- CountDownLatch与CyclicBarrier区别
1.CountDownLatch由第三方线程放行,CyclicBarrier由自己放行
2.CountDownLatch放行条件>=线程数,CyclicBarrier放行条件=线程数
4.Exchanger
两个线程间数据交换
exchange():当另一个线程没有调用exchange时,程序在此处阻塞
返回值是交换到的内容
转账时发现钱不够时,又要转回来
5.Semaphore
控制同时访问某资源的线程数量(流量控制)
Semaphore(初始数量)
acquire():-1
release():+1
6.Callable/FutureTask
public class UseFuture {
private static class UseCallable implements Callable<Integer> {
private int sum;
@Override
public Integer call() throws Exception {
System.out.println("Callable中call()开始计算");
Thread.sleep(2000);
for (int i = 0; i < 5000; i++) {
sum += i;
}
System.out.println("Callable中call()计算结束,结果=" + sum);
return sum;
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException, TimeoutException {
UseCallable useCallable = new UseCallable();
FutureTask<Integer> futureTask = new FutureTask<>(useCallable);
new Thread(futureTask).start();
Random random = new Random();
Thread.sleep(1);
if (random.nextBoolean()) {
System.out.println("--获取结果--");
System.out.println("阻塞有参get获取Callable结果:" + futureTask.get(5, TimeUnit.SECONDS));
System.out.println("阻塞式get()阻塞结束");
} else {
System.out.println("中断计算");
futureTask.cancel(true);
}
}
}