天下之事,必先处之难,而后易之。

Java并发编程线程任务返回值及顺序问题解决方案

目录

核心知识点 

无返回值并发执行顺序控制 

有返回值或先后顺序控制

Future FutureTask CompletionService CompletableFutrue比较

可回调实现方式

Callable

Supplier

并发工具类

CountDownLatch

CyclicBarrier

FutureTask

CompletionService

CompletableFuture


核心知识点 

无返回值并发执行顺序控制 

  • CountDownLatch
  • CyclicBarrier

有返回值或先后顺序控制

  • FutureTask
  • CompletionService
  • CompletableFuture

Future FutureTask CompletionService CompletableFutrue比较

下图参考自:https://blog.csdn.net/u011726984/article/details/79320004

可回调实现方式

Callable

接口定义:

@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

接口实现:

package thread;

import java.util.Random;
import java.util.concurrent.Callable;
/**
 * 
 * @function  功能:线程可回调任务
 * @author    PJL
 * @package   thread
 * @filename  CountTask.java
 * @time      2020年4月1日 下午12:50:16
 */
public class CallableTask implements Callable<Integer>{

	@Override
	public Integer call() throws Exception {
		int count=new Random().nextInt(10000);
		Thread.sleep(count);
		System.out.println("---"+count);
		return count;
	}

}

Supplier

接口定义:

@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

接口实现:

package thread;

import java.util.Random;
import java.util.function.Supplier;
/**
 * 
 * @function  功能:可回调的Supplier顺序处理线程任务
 * @author    PJL
 * @package   thread
 * @filename  SupplierTask.java
 * @time      2020年4月1日 下午1:06:27
 */
public class SupplierTask implements Supplier<Integer>{

	@Override
	public Integer get() {
		int count=new Random().nextInt(10000);
		try {
			Thread.sleep(count);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("---"+count);
		return count;
	}

}

并发工具类

CountDownLatch

CountDownLatch 中文名叫闭锁,通俗的叫法叫栅栏发令枪。它可以模拟用户同时到达开始并发执行业务的场景,比如秒杀。

package thread;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.CountDownLatch;
/**
 * 同步辅助类CountDownLatch等待组线程执行完毕
 * @author admin
 * @link {@link https://www.cnblogs.com/liun1994/p/7396026.html}
 * @screen 场景:
 * <li>分布式计算进行汇总最终结果</li>
 * <li>主线程等待子线程执行完的操作</li>
 * <li>等待最终执行如初始化资源完成操作</li>
 * <li>等待最终执行如系统资源汇总计算</li>
 */
public class WorkerCountDownLatch {

	final static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

	public static void main(String[] args) throws InterruptedException {
		CountDownLatch latch = new CountDownLatch(2);// 两个工人的协作
		Worker worker1 = new Worker("zhang san", 5000, latch);
		Worker worker2 = new Worker("li si", 8000, latch);
		worker1.start();//线程就绪
		worker2.start();//线程就绪
		latch.await();// 等待所有工人完成工作
		System.out.println("all work done at " + sdf.format(new Date()));
	}

	static class Worker extends Thread {
		String workerName;
		int workTime;
		CountDownLatch latch;

		public Worker(String workerName, int workTime, CountDownLatch latch) {
			this.workerName = workerName;
			this.workTime = workTime;
			this.latch = latch;
		}

		public void run() {
			System.out.println("Worker " + workerName + " do work begin at " + sdf.format(new Date()));
			doWork();// 工作了
			System.out.println("Worker " + workerName + " do work complete at "	+ sdf.format(new Date()));
			latch.countDown();// 工人完成工作,计数器减一

		}

		private void doWork() {
			try {
				Thread.sleep(workTime);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

}

测试结果:

Worker zhang san do work begin at 2020-04-01 13:47:45
Worker li si do work begin at 2020-04-01 13:47:45
Worker zhang san do work complete at 2020-04-01 13:47:50
Worker li si do work complete at 2020-04-01 13:47:53
all work done at 2020-04-01 13:47:53

 

CyclicBarrier

CyclicBarrier内部采用了可重入锁ReentrantLock和Runnable接口,可以控制多任务循环串行。

package thread;

import java.util.concurrent.CyclicBarrier;
/**
 * 
 * @function  功能:CyclicBarrier允许线程之间互相等待
 * @author    PJL
 * @package   thread
 * @filename  WorkerCyclicBarrier.java
 * @time      2020年4月1日 下午1:27:51
 */
public class WorkerCyclicBarrier {

	static class TaskThread extends Thread {

		CyclicBarrier barrier;

		public TaskThread(CyclicBarrier barrier) {
			this.barrier = barrier;
		}

		@Override
		public void run() {
			try {
				// 循环执行A直到完成
				Thread.sleep(1000);
				System.out.println(getName() + " 执行任务A");
				barrier.await();
				System.out.println(getName() + " 执行任务 A完成");

				// 循环执行B直到完成
				Thread.sleep(2000);
				System.out.println(getName() + " 执行任务B");
				barrier.await();
				System.out.println(getName() + " 执行任务 B完成");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	public static void main(String[] args) {
		int threadNum = 5;
		CyclicBarrier barrier = new CyclicBarrier(threadNum, new Runnable() {

			@Override
			public void run() {
				// 回调处理
				System.out.println(Thread.currentThread().getName() + " 完成最后任务");
			}
		});

		for (int i = 0; i < threadNum; i++) {
			new TaskThread(barrier).start();
		}
	}

}

运行打印结果:

Thread-0 执行任务A
Thread-1 执行任务A
Thread-2 执行任务A
Thread-4 执行任务A
Thread-3 执行任务A
Thread-3 完成最后任务
Thread-3 执行任务 A完成
Thread-2 执行任务 A完成
Thread-0 执行任务 A完成
Thread-4 执行任务 A完成
Thread-1 执行任务 A完成
Thread-0 执行任务B
Thread-4 执行任务B
Thread-3 执行任务B
Thread-2 执行任务B
Thread-1 执行任务B
Thread-1 完成最后任务
Thread-1 执行任务 B完成
Thread-2 执行任务 B完成
Thread-3 执行任务 B完成
Thread-4 执行任务 B完成
Thread-0 执行任务 B完成

FutureTask

FutureTask 实现了RunnableFuture接口

/**
 * A cancellable asynchronous computation.  This class provides a base
 * implementation of {@link Future}, with methods to start and cancel
 * a computation, query to see if the computation is complete, and
 * retrieve the result of the computation.  The result can only be
 * retrieved when the computation has completed; the {@code get}
 * methods will block if the computation has not yet completed.  Once
 * the computation has completed, the computation cannot be restarted
 * or cancelled (unless the computation is invoked using
 * {@link #runAndReset}).
 *
 * <p>A {@code FutureTask} can be used to wrap a {@link Callable} or
 * {@link Runnable} object.  Because {@code FutureTask} implements
 * {@code Runnable}, a {@code FutureTask} can be submitted to an
 * {@link Executor} for execution.
 *
 * <p>In addition to serving as a standalone class, this class provides
 * {@code protected} functionality that may be useful when creating
 * customized task classes.
 *
 * @since 1.5
 * @author Doug Lea
 * @param <V> The result type returned by this FutureTask's {@code get} methods
 */
public class FutureTask<V> implements RunnableFuture<V> {

而RunnableFutrue接口继承自Runnable和Future接口

/**
 * A {@link Future} that is {@link Runnable}. Successful execution of
 * the {@code run} method causes completion of the {@code Future}
 * and allows access to its results.
 * @see FutureTask
 * @see Executor
 * @since 1.6
 * @author Doug Lea
 * @param <V> The result type returned by this Future's {@code get} method
 */
public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}

FutureTask测试:

package thread;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
/**
 * 
 * @function  功能:FutureTask线程返回值获取方式
 * @author    PJL
 * @package   thread
 * @filename  WorkerFutureTask.java
 * @time      2020年4月1日 下午1:11:41
 */
public class WorkerFutureTask {
	
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		ExecutorService executor = Executors.newCachedThreadPool();
		FutureTask<Integer> task1 = new FutureTask<Integer>(new CallableTask());
		FutureTask<Integer> task2 = new FutureTask<Integer>(new CallableTask());
		FutureTask<Integer> task3 = new FutureTask<Integer>(new CallableTask());
		executor.execute(task1);
		executor.execute(task2);
		executor.execute(task3);
		long start = System.currentTimeMillis();
		System.out.println("task1结果=" + task1.get());
		System.out.println("task2结果=" + task2.get());
		System.out.println("task3结果=" + task3.get());
		long end = System.currentTimeMillis();
		System.out.println("总共耗时=" + (end - start) + "ms");
	}

}

测试结果:

---181
---2594
task1结果=2594
task2结果=181
---2816
task3结果=2816
总共耗时=2817ms

 

注意:FutureTask的get()方法是阻塞的,不区分完成先后顺序,所以最长的时间可能是加起来所有任务耗时的总和。 

CompletionService

CompletionService 是通过线程干预的模式对线程完成状态进行监控,它是JDK并发包的接口,其实现是java.util.concurrent.ExecutorCompletionService,需要结合线程池来使用。

测试示例:

package thread;

import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
 * 
 * @function  功能:线程完成顺序干预先后排序
 * @author    PJL
 * @package   thread
 * @filename  WorkerCompletionService.java
 * @time      2020年4月1日 下午1:20:14
 */
public class WorkerCompletionService {
	
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		ExecutorService executor = Executors.newCachedThreadPool();
		CompletionService<Integer> completionService=new ExecutorCompletionService<Integer>(executor);
		Future<Integer> task1=completionService.submit(new CallableTask());
		Future<Integer> task2=completionService.submit(new CallableTask());
		Future<Integer> task3=completionService.submit(new CallableTask());
		long start = System.currentTimeMillis();
		System.out.println("task1结果=" + task1.get());
		System.out.println("task2结果=" + task2.get());
		System.out.println("task3结果=" + task3.get());
		long end = System.currentTimeMillis();
		System.out.println("总共耗时=" + (end - start) + "ms");
	}

}

测试结果:

---1539
task1结果=1539
---5169
task2结果=5169
---9412
task3结果=9412
总共耗时=9414ms

 

CompletableFuture

CompletableFuture 实现了Future和CompletionState接口,可实现线程先后完成排序。

public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {

测试示例:

package thread;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 
 * @function 功能:多线程任务按照完成先后顺序返回
 * @author PJL
 * @package thread
 * @filename WorkerCompletableFuture.java
 * @time 2020年4月1日 下午1:04:00
 */
public class WorkerCompletableFuture {

	public static void main(String[] args) throws InterruptedException,	ExecutionException {
		ExecutorService executor = Executors.newCachedThreadPool();
		CompletableFuture<Integer> task1 = CompletableFuture.supplyAsync(new SupplierTask(), executor);
		CompletableFuture<Integer> task2 = CompletableFuture.supplyAsync(new SupplierTask(), executor);
		CompletableFuture<Integer> task3 = CompletableFuture.supplyAsync(new SupplierTask(), executor);
		long start = System.currentTimeMillis();
		System.out.println("task1结果=" + task1.get());
		System.out.println("task2结果=" + task2.get());
		System.out.println("task3结果=" + task3.get());
		long end = System.currentTimeMillis();
		System.out.println("总共耗时=" + (end - start) + "ms");
	}

}

测试结果:

---609
---782
task1结果=782
task2结果=609
---5614
task3结果=5614
总共耗时=5615ms

 

posted @ 2024-01-24 17:27  boonya  阅读(44)  评论(0)    收藏  举报  来源
我有佳人隔窗而居,今有伊人明月之畔。
轻歌柔情冰壶之浣,涓涓清流梦入云端。
美人如娇温雅悠婉,目遇赏阅适而自欣。
百草层叠疏而有致,此情此思怀彼佳人。
念所思之唯心叩之,踽踽彳亍寤寐思之。
行云如风逝而复归,佳人一去莫知可回?
深闺冷瘦独自徘徊,处处明灯影还如只。
推窗见月疑是归人,阑珊灯火托手思忖。
庐居闲客而好品茗,斟茶徐徐漫漫生烟。

我有佳人在水之畔,瓮载渔舟浣纱归还。
明月相照月色还低,浅近芦苇深深如钿。
庐山秋月如美人衣,画堂春阁香气靡靡。
秋意幽笃残粉摇曳,轻轻如诉画中蝴蝶。
泾水潺潺取尔浇园,暮色黄昏如沐佳人。
青丝撩弄长裙翩翩,彩蝶飞舞执子手腕。
香带丝缕缓缓在肩,柔美体肤寸寸爱怜。
如水之殇美玉成欢,我有佳人清新如兰。
伊人在水我在一边,远远相望不可亵玩。