java并发框架Executor
并行计算(1)
- 业务:任务多,数据量大
- 串行 vs 并行
– 串行编程简单,并行编程困难
– 单个计算核频率下降,计算核数增多,整体性能变高 - 并行困难(任务分配和执行过程高度耦合)
– 如何控制粒度,切割任务
– 如何分配任务给线程,监督线程执行过程
并行计算(2)
- 并行模式
– 主从模式(Master - Slave)
– Workerr模式(Workerr - Worker) - Java并发编程
– Thread\Runnable\Thread组管理
– Executor
– Fork - Join框架
线程组管理
- 线程组ThreadGroup
– 线程的集合
– 树形结构,大线程组可以包括小线程组
– 可以通过enumerate方法遍历组内的线程,执行操作
– 能够有效管理多个线程,但是管理效率低
– 任务分配和执行过程高度耦合
– 重复创建线程、关闭线程操作,无法重用线程
线程和线程组内的线程,都是new产生出来的,start一次之后,就不能再次使用(再次start),new 的代价很昂贵,只能运行一次,性价比过低
线程组ThreadGroup例子:
- activeCount,返回线程组中还处于active的线程数(估计数);
- enumerate,将线程组中active的线程拷贝到数组中;
- interrupt,对线程组中所有的线程发出interrupt信号;
- list,打印线程组中所有的线程信息。
package com.torey.threadgroup;
/**
* @ClassName:Result
* @Description:搜索结果类
* @author: Torey
*/
public class Result {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.torey.threadgroup;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.TimeUnit;
/**
* @ClassName:Searcher
* @Description:
* @author: Torey
*/
public class Searcher implements Runnable {
private Result result;
public Searcher(Result result) {
this.result = result;
}
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.printf("Thread %s: 启动\n",name);
try{
doTask();
result.setName(name);
}
catch (Exception ex){
System.out.printf("Thread %s: 被中断\n",name);
// ex.printStackTrace();
return;
}
System.out.printf("Thread %s: 完成\n",name);
}
private void doTask() throws InterruptedException {
Random random = new Random((new Date()).getTime());
int value= (int)(random.nextDouble()*100);
System.out.printf("Thread sleep %s: %d\n",Thread.currentThread().getName(),value);
TimeUnit.SECONDS.sleep(value);
}
}
package com.torey.threadgroup;
import java.util.concurrent.TimeUnit;
/**
* @ClassName:Main
* @Description:
* @author: Torey
*/
public class Main {
public static void main(String[] args){
ThreadGroup threadGroup = new ThreadGroup("Searcher");
Result result = new Result();
//创建一个任务,10个线程完成
Searcher searcherTask = new Searcher(result);
for (int i = 0; i < 10; i++) {
Thread thread= new Thread(threadGroup,searcherTask);
thread.start();
try{
TimeUnit.SECONDS.sleep(1);
}catch (Exception ex){
ex.printStackTrace();
}
}
System.out.println("=======00000=======");
/**
* activeCount,返回线程组中还处于active的线程数(估计数);
* enumerate,将线程组中active的线程拷贝到数组中;
* interrupt,对线程组中所有的线程发出interrupt信号;
* list,打印线程组中所有的线程信息。
*/
//查看线程组消息
System.out.printf("active 线程数量:%d\n",threadGroup.activeCount());
System.out.printf("list 线程明细1:");
threadGroup.list();
System.out.printf("list 线程明细2:");
System.out.println("=======22222=======");
//遍历线程组
//activeCount,返回线程组中还处于active的线程数(估计数);
Thread[] threads = new Thread[threadGroup.activeCount()];
//将线程组中active的线程拷贝threads数组中
threadGroup.enumerate(threads);
for (int i = 0; i < threadGroup.activeCount(); i++) {
System.out.printf("Thread %s: %s\n", threads[i].getName(), threads[i].getState());
}
System.out.println("=======33333=======");
waitFinish(threadGroup);
//对所有的线程发出interrupt信号
threadGroup.interrupt();
System.out.println("=======5555=======");
}
//因为一共有10个线程,这里是等10个线程都完成后,就执行好了
public static void waitFinish(ThreadGroup threadGroup){
while (threadGroup.activeCount()>9){
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Executor
- 从JDK5 开始提供Executor FrameWork (java.util.concurrent.*)
– 分离任务的创建和执行者的创建
– 线程重复利用**(new 线程代价很大)** - 理解共享线程池的概念
– 预设好多个Thread,可弹性增加
– 多次执行很多很小的任务
– 任务创建和执行过程解耦
– 程序员无需关心线程池执行任务过程 - 主要类: ExecutorService,ThreadPoolExecutor,Future
– Executors.newCachedThreadPool / newFixedThreadPool 创建线程池
– ExecutorsService 线程池服务,代表整个线程池
– Callable 具体的逻辑对象(线程类)
– Future 返回结果
Callable和Runnable是等价的,可以用来执行一个任务。Runnable的run方法没有返回值,而Callable的call方法可以有返回值
Executo实例1:
package com.torey.executor1;
import java.sql.SQLOutput;
import java.util.concurrent.TimeUnit;
/**
* @ClassName:Task
* @Description:
* @author: Torey
*/
public class Task implements Runnable {
private String name;
public Task(String name) {
this.name = name;
}
@Override
public void run() {
Long duration= (long) (Math.random()*1000);
System.out.printf("%s: Task %s :Doing a task during %d seconds\n",
Thread.currentThread().getName(),name,duration);
try {
Thread.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("%s: Task %s: Finished on: %s \n",
Thread.currentThread().getName(),name,duration);
}
}
package com.torey.executor1;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
/**
* @ClassName:Server
* @Description:执行服务器
* @author: Torey
*/
public class Server {
//线程池
private ThreadPoolExecutor executor;
public Server() {
//创建线程池,默认是随着任务的量,自己增长的
executor=(ThreadPoolExecutor) Executors.newCachedThreadPool();
//创建固定个数的线程池
// executor=(ThreadPoolExecutor) Executors.newCachedThreadPool(5);
}
//向线程池提交任务
public void submitTask(Task task){
System.out.printf("Server: A new task has arrived\n");
//执行 无返回值
executor.execute(task);
System.out.printf("Server:Pool Size:%d\n",executor.getPoolSize());
System.out.printf("Server:Active Count:%d\n",executor.getActiveCount());
System.out.printf("Server:Completed Tasks:%d\n",executor.getCompletedTaskCount());
}
public void endServer(){
executor.shutdown();
}
}
package com.torey.executor1;
/**
* @ClassName:Main
* @Description:
* @author: Torey
*/
public class Main {
public static void main(String[] args) throws InterruptedException {
//创建一个执行服务器
Server server = new Server();
//创建100个任务,并发给执行器,等待完成
for (int i = 0; i < 100; i++) {
Task task = new Task("Task" + i);
Thread.sleep(10);
server.submitTask(task);
}
//关闭整个线程池
server.endServer();
}
}
Executo实例2:
使用Executor和Callable接口实现:1–100000所有的和:
package com.torey.executor2;
import java.util.Random;
import java.util.concurrent.Callable;
/**
* @ClassName:SumTask
* @Description:
* @author: Torey
*/
public class SumTask implements Callable<Integer> {
private int startNumber;
private int endNumber;
public SumTask(int stare,int end) {
this.startNumber=stare;
this.endNumber=end;
}
@Override
public Integer call() throws Exception {
int sum=0;
for (int i = startNumber; i <= endNumber; i++) {
sum+=i;
}
Thread.sleep( new Random().nextInt(1000));
System.out.printf("%s: %d 到 %d 的和为: %d\n",Thread.currentThread().getName(),this.startNumber,this.endNumber,sum);
return sum;
}
}
package com.torey.executor2;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
/**
* @ClassName:SumTest
* @Description:
* @author: Torey
*/
public class SumTest {
public static void main(String[] args) throws InterruptedException {
//执行线程池
ThreadPoolExecutor executor= (ThreadPoolExecutor) Executors.newFixedThreadPool(4);
List<Future<Integer>> futures=new ArrayList<>();
//统计1-100000总和,分成10个任务计算,提交任务
for (int i = 0; i < 10; i++) {
SumTask sumTask = new SumTask(i * 100 + 1, (i + 1) * 100);
Future<Integer> submit = executor.submit(sumTask);
futures.add(submit);
}
//每隔50毫秒,轮询等待10个任务结束
do{
System.out.printf("Main:已经完成多少个任务,%d\n",executor.getCompletedTaskCount());
for (int i = 0; i < futures.size(); i++) {
Future<Integer> result = futures.get(i);
System.out.printf("Main:Task %d: %s\n",i,result.isDone());
}
Thread.sleep(100);
}while (executor.getCompletedTaskCount()<futures.size());
//所有任务都已经结束了,综合计算结果
int total=0;
for (int i = 0; i < futures.size(); i++) {
Future<Integer> result2 = futures.get(i);
Integer sum =null;
try {
//获取每个线程的和
sum=result2.get();
total+=sum;
} catch (ExecutionException e) {
e.printStackTrace();
}
}
System.out.println("1--100000的和为:" + total);
//关闭线程池
executor.shutdown();
}
}