第四章 Thread Executors(Executors多线程架构)【上】

本章涉及内容:

  • 创建一个executor线程
  • 创建一个固定大小executor
  • 执行executor任务返回一个结果
  • 处理多任务和处理第一个结果
  • 处理多任务和处理所有结果
  • 延迟之后运行executor
  • 周期地运行任务的executor
  • 在executor取消任务
  • 在executor控制任务完成
  • 在executor分开task启动和处理结果
  • 控制executor的拒绝的任务

简介:

executor是一个为了解决出现大量线程的时候,executor管理和处理线程。

1、创建一个executor线程

例子:模拟web服务接收处理多个客户端请求

package com.jack;

import java.util.Date;
import java.util.concurrent.TimeUnit;

public class Task implements Runnable {

	private Date initDate;
	private String name;
	
	public Task(String name){
		initDate = new Date();
		this.name = name;
	}
	@Override
	public void run() {
		System.out.printf("%s: Task %s:创建日期:%s\n", Thread.currentThread().getName(),
				name, initDate);
		System.out.printf("%s: Task %s: 启动日期:%s\n", Thread.currentThread().getName(),
				name, new Date());
		try{
			Long duration = (long) (Math.random()*10);
			System.out.printf("%s: Task %s: 正在执行任务持续 %d 秒\n", Thread.currentThread().getName(),name, duration);
			TimeUnit.SECONDS.sleep(duration);
		} catch (InterruptedException e){
			e.printStackTrace();
		}
		
		System.out.printf("%s: Task %s: 完成日期: %s\n", Thread.currentThread().getName(), name, new Date());
	}

}

package com.jack;

import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

public class Server {
	
	private ThreadPoolExecutor executor;
	
	public Server(){
		executor = (ThreadPoolExecutor) Executors.newCachedThreadPool();
	}
	
	public void executeTask(Task task){
		System.out.printf("服务器:一个新的任务已经到达\n");
		executor.execute(task);
		System.out.printf("服务器:线程池的大小: %d\n", executor.getPoolSize());
		System.out.printf("服务器:激活的数量:%d\n", executor.getActiveCount());
		System.out.printf("服务器:完成任务的数量: %d\n", executor.getCompletedTaskCount());
		
		
	}
	public void endServer(){
		executor.shutdown();
	}
}
package com.jack;

public class Main {
	public static void main(String[] args) {
		Server server = new Server();
		for (int i=0; i<10; i++){
			Task task = new Task("Task  " + i);
			server.executeTask(task);
		}
		server.endServer();
	}
}

日志:

总结:

  • 1、只要实现Runnable接口的线程类,然后通过Executor进行执行(execute(task)方法)启动的线程
  • 2、最后关闭Executor管理器(ThreadPoolExecutor)

2、创建固定大小的Executor

只需修改一个Server类

package com.jack;

import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

public class Server {
	
	private ThreadPoolExecutor executor;
	
	public Server(){
		executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);
	}
	
	public void executeTask(Task task){
		System.out.printf("服务器:一个新的任务已经到达\n");
		executor.execute(task);
		System.out.printf("服务器:线程池的大小: %d\n", executor.getPoolSize());
		System.out.printf("服务器:激活的数量:%d\n", executor.getActiveCount());
		System.out.printf("服务器:完成任务的数量: %d\n", executor.getCompletedTaskCount());
		System.out.printf("服务器:任务的数量: %d\n", executor.getTaskCount());
		
		
	}
	public void endServer(){
		executor.shutdown();
	}
}

修改点:

1、Executors.newFixedThreadPool(5);固定大小为5

2、executeTask(task) 增加日志 System.out.printf("服务器:任务的数量: %d\n", executor.getTaskCount());

日志:



总结:

  • 1、如果只是运行一个线程呢,那么使用newSingleThreadExecutor()方法。

3、在executor任务返回一个结果

Callable: 这个接口有一个call()方法,调用这个方法返回结果

Future : 这个接口获取Callable接口生成的结果。

例子:学习斐波拉契数列

package com.jack;

import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;

public class FactorialCalculator implements Callable<Integer> {

	private Integer number;
	
	public FactorialCalculator(Integer number) {
		super();
		this.number = number;
	}

	@Override
	public Integer call() throws Exception {
		int result =1;
		if((number==0) || (number==1)) {
			result=1;
		}else {
			for (int i=2; i<=number; i++){
				result*=i;
				TimeUnit.MILLISECONDS.sleep(20);
			}
		}
		System.out.printf("FactorialCalculator===%s: %d     %d\n", Thread.currentThread().getName(),result,number);
		
		return result;
	}
	
}

总结:首先实现Callable<Integer>接口(Integer表示返回结果类型)

package com.jack;


import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

package com.jack;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class Main {
	public static void main(String[] args) {
		ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);
		List<Future<Integer>> resultList =new ArrayList<>();
		Random random = new Random();
		
		for(int i=0; i<10; i++){
			Integer number = random.nextInt(10);
			FactorialCalculator calculator = new FactorialCalculator(number);
			Future<Integer> result = executor.submit(calculator);
			resultList.add(result);
		}
		do {
			System.out.printf("Main: 完成的任务的数量: %d\n", executor.getCompletedTaskCount());
			
			for (int i=0; i<resultList.size(); i++){
				Future<Integer> result = resultList.get(i);
				System.out.printf("Main : 任务 %d : %s\n", i, result.isDone());
			}
			try {
				TimeUnit.MILLISECONDS.sleep(50);
				
			}catch (InterruptedException e){
				e.printStackTrace();
			}
		} while (executor.getCompletedTaskCount() < resultList.size());
		
		System.out.printf("Main: 结果 \n");
		for (int i=0; i <resultList.size(); i++){
			Future<Integer> result = resultList.get(i);
			Integer number = null;
			try{
				number= result.get();
				
			}catch (InterruptedException e){
				e.printStackTrace();
			} catch (ExecutionException e) {
				e.printStackTrace();
			}
			System.out.printf("Main: 任务 %d : %d\n", i,number);
		}
		executor.shutdown();
	}
}

总结:

  • 1、创建一个固定大小为2的线程池
  • 2、创建接受结果的List<Future<Integer>> 集合
  • 3、循环创建十个实现Callable接口的实例,然后用线程池的submit()方法,它将返回一个执行的结果(这个结果不会立即返回,这里只是注册)
  • 4、通过判断线程池完成的数量是否等于注册的数量。结果isDone()方法也可以判断结果是否返回。
  • 5、最后循环打印结果,get()方法(如果没有结果返回会一直阻塞)

4、运行多个线程处理第一个结果。

类似比赛时候,我们只关心谁第一个到达终点。或者是验证排序算法的优越性

package com.jack;

import java.util.Random;
import java.util.concurrent.TimeUnit;

public class UserValidator {

	private String name;

	public UserValidator(String name) {
		super();
		this.name = name;
	}
	
	public boolean validate(String name, String password){
		Random random = new Random();
		try {
			long duration = (long) (Math.random()*10);
			System.out.printf("验证 %s: 验证一个用户花费 %d 秒\n", this.name, duration);
			TimeUnit.SECONDS.sleep(duration);
		} catch (InterruptedException e) {
			return false;
		}
		return random.nextBoolean();
	}

	public String getName() {
		return name;
	}
	
}

总结:

        1、创建一个验证用户的类,随机验证

package com.jack;

import java.util.concurrent.Callable;

public class TaskValidator implements Callable<String>{

	private UserValidator validator;
	
	private String user;
	private String password;
	
	public TaskValidator(UserValidator validator, String user, String password) {
		super();
		this.validator = validator;
		this.user = user;
		this.password = password;
	}

	@Override
	public String call() throws Exception {
		if(!validator.validate(user, password)){
			System.out.printf("%s: 这个用户没有找到\n", validator.getName());
			throw new Exception ("用户验证失败");
		}
		System.out.printf("%s: 用户已经找到\n", validator.getName());
		return validator.getName();
	}

}
package com.jack;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Main {
	public static void main(String[] args) {
		String username = "test";
		String password = "test";
		UserValidator ldapValidator = new UserValidator("LDAP");
		UserValidator dbValidator = new UserValidator("dataBase");
		
		TaskValidator ldapTask = new TaskValidator(ldapValidator, username, password);
		
		TaskValidator dbTask = new TaskValidator(dbValidator, username, password);
		List<TaskValidator> taskList =new ArrayList<>();
		taskList.add(ldapTask);
		taskList.add(dbTask);
		ExecutorService executor = Executors.newCachedThreadPool();
		String result;
		try {
			result = executor.invokeAny(taskList);
			System.out.printf("Main : 结果: %s\n", result);
		}catch (InterruptedException e){
			e.printStackTrace();
		}catch (ExecutionException e){
			e.printStackTrace();
		}
		executor.shutdown();
		System.out.printf("Main : Execution执行结束\n");
				
	}
}


总结:

  • 1、创建用户验证。
  • 2、创建一个newCachedThreadPool() 返回一个ExecutorService. 
  • 3、executor.invokeAny(taskList) 表示只要其中有个call方法执行完获取最新的结果。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值