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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章