java线程池

java 创建线程池

线程池都是通过线程池工厂创建,再调用线程池中的方法获取线程,再通过线程去执行任务方法。

Executors:线程池创建工厂类
public static ExecutorServicenewFixedThreadPool(int nThreads):返回线程池对象
ExecutorService:线程池类
Future<?> submit(Runnable task):获取线程池中的某一个线程对象,并执行
Future 接口:用来记录线程任务执行完毕后产生的结果。线程池创建与使用

这里介绍两种使用线程池创建线程的方法

1):使用Runnable接口创建线程池

使用线程池中线程对象的步骤:

1、创建线程池对象
2、创建 Runnable 接口子类对象
3、提交 Runnable 接口子类对象
4、关闭线程池

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

class TaskRunnable implements Runnable{
	@Override
	public void run() {
		for (int i = 0; i < 1000; i++) {
			System.out.println("自定义线程任务在执行"+i);
		}
	}
}

public class Test {
	public static void main(String[] args) {
	//创建线程池对象  参数5,代表有5个线程的线程池
	ExecutorService service = Executors.newFixedThreadPool(5);
	//创建Runnable线程任务对象
	TaskRunnable task = new TaskRunnable();
	//从线程池中获取线程对象
	service.submit(task);
	System.out.println("----------------------");
	//再获取一个线程对象
	service.submit(task);
	//关闭线程池
	service.shutdown();
	}
}

2)使用Callable接口创建线程池

Callable接口:与Runnable接口功能相似,用来指定线程的任务。其中的call()方法,用来返回线程任务执行完毕后的结果,call方法可抛出异常。

ExecutorService:线程池类

Future submit(Callable task):获取线程池中的某一个线程对象,并执行线程中的 call() 方法

Future 接口:用来记录线程任务执行完毕后产生的结果。线程池创建与使用

使用线程池中线程对象的步骤:

1、创建线程池对象
2、创建 Callable 接口子类对象
3、提交 Callable 接口子类对象
4、关闭线程池

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Callable;

class TaskCallable implements Callable<Object>{
	@Override
	public Object call() throws Exception {
		for (int i = 0; i < 1000; i++) {
			System.out.println("自定义线程任务在执行"+i);
		}
		return null;
	}
}

public class Test{
	public static void main(String[] args) {
		ExecutorService service = Executors.newFixedThreadPool(3);
		TaskCallable c = new TaskCallable();
		//线程池中获取线程对象,调用run方法
		service.submit(c);
		//再获取一个
		service.submit(c);
		//关闭线程池
		service.shutdown();
	}
}

用 CompletableFuture 来解决回调的问题。

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;

public class CompletableFutureDemo {
	public static void main(String[] args) throws InterruptedException {
		long l = System.currentTimeMillis();
		CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(() -> {
			System.out.println("执行耗时操作...");
			timeConsumingOperation();
			return 100;
		});
		completableFuture.whenComplete((result, e) -> {
			System.out.println("结果:" + result);
		});
		System.out.println("主线程运算耗时:" + (System.currentTimeMillis() - l) + " ms");
		new CountDownLatch(1).await();
	}

	static void timeConsumingOperation() {
		try {
			Thread.sleep(3000);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

Future 的局限性

  1. 不能手动完成
    当你写了一个函数,用于通过一个远程API获取一个电子商务产品最新价格。因为这个 API 太耗时,你把它允许在一个独立的线程中,并且从你的函数中返回一个 Future。现在假设这个API服务宕机了,这时你想通过该产品的最新缓存价格手工完成这个Future 。你会发现无法这样做。

  2. Future 的结果在非阻塞的情况下,不能执行更进一步的操作
    Future 不会通知你它已经完成了,它提供了一个阻塞的 get() 方法通知你结果。你无法给 Future 植入一个回调函数,当 Future 结果可用的时候,用该回调函数自动的调用 Future 的结果。
    3.多个 Future 不能串联在一起组成链式调用 有时候你需要执行一个长时间运行的计算任务,并且当计算任务完成的时候,你需要把它的计算结果发送给另外一个长时间运行的计算任务等等。你会发现你无法使用 Future 创建这样的一个工作流。
    4.不能组合多个 Future 的结果 假设你有10个不同的Future,你想并行的运行,然后在它们运行未完成后运行一些函数。你会发现你也无法使用 Future 这样做。
    5.没有异常处理 Future API 没有任务的异常处理结构居然有如此多的限制,幸好我们有CompletableFuture,你可以使用 CompletableFuture 达到以上所有目的。

CompletableFuture

CompletableFuture 实现了 Future 和 CompletionStage接口,并且提供了许多关于创建,链式调用和组合多个 Future 的便利方法集,而且有广泛的异常处理支持。

阿里推荐使用

ExecutorService executor =new ThreadPoolExecutor(........)

Java 8 CompletableFuture 教程

Java 8 CompletableFuture 教程

posted @ 2020-12-09 14:49  rm-rf*  阅读(65)  评论(0编辑  收藏  举报