Java高并发编程(四)
一、Executor执行器
1.Executor接口,java线程池框架中的顶层接口,提供一个execute方法来执行任务
import java.util.concurrent.Executor; public class T01_MyExecutor implements Executor { public static void main(String[] args) {
new T01_MyExecutor().execute(()->System.out.println("hello executor"));
} @Override
public void execute(Runnable command) {
//new Thread(command).run();//另起线程方法调用
command.run();//方法直接调用
} }
2.任务接口
1)callable接口:提供一个call方法,具有返回值可以抛出异常
2)runnable接口:提供一个run方法,无返回值不可抛出异常
3.ExecutorService接口(Executor的一个子接口)
1)ExecutorService可以理解为服务,执行execute方法可以向服务器中添加runnable任务无返回值,而执行submit方法可以向服务中添加callable与runnable任务,且有返回值
2)Executor与ExecutorService的简单理解:可以想象许多的执行器Executor在等待着执行任务,而service服务可通过调用execute或submit方法来添加不同的任务供执行器执行
3)submit方法具有一个future类型的返回值,与callable,Executors一起使用
public class T06_Future {
public static void main(String[] args) throws InterruptedException, ExecutionException { FutureTask<Integer> task = new FutureTask<>(()->{
TimeUnit.MILLISECONDS.sleep(500);
return 1000;
}); //new Callable () { Integer call();} new Thread(task).start(); System.out.println(task.get()); //阻塞 //*******************************
ExecutorService service = Executors.newFixedThreadPool(5);
Future<Integer> f = service.submit(()->{
TimeUnit.MILLISECONDS.sleep(500);
return 1;
});
System.out.println(f.get());
System.out.println(f.isDone()); }
}
运行结果:
4.Executors(操作Executor的一个工具类、工厂类)
二、ThreadPool线程池
1.线程池将任务分配给池中线程,当线程池中线程执行不过来时,任务会进入等待队列,队列由BlockingQueue实现,当有线程空闲时再来任务时会被分配给空闲线程,一个线程同时维护着两个队列(结束队列与等待队列)
下面一个程序帮助理解线程池的概念
public class T05_ThreadPool {
public static void main(String[] args) throws InterruptedException {
ExecutorService service = Executors.newFixedThreadPool(5); //execute submit
for (int i = 0; i < 6; i++) {
service.execute(() -> {
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
});
}
System.out.println(service); service.shutdown();//正常关闭,等待所有任务执行完毕,关闭线程池
System.out.println(service.isTerminated());//判断所有任务是否都执行完了
System.out.println(service.isShutdown());//判断线程池是否被关闭了
System.out.println(service); TimeUnit.SECONDS.sleep(5);
System.out.println(service.isTerminated());
System.out.println(service.isShutdown());
System.out.println(service);
}
}
运行结果:
2.六种线程池
1)FixedThreadPool 固定线程数量的线程池
2)cachedThreadPool 假定刚开始一个线程都没有,来一个任务开启一个线程,如果再来一个任务,线程池中有空闲线程就将任务分配给空闲线程,如此往复直到起到电脑能支撑限度为止,默认一个线程空闲超过一分钟就自动销毁
3)singleThreadPool 线程池中只有一个线程
4)scheduledThreadPool 定时器线程池
5)workStealingPool 工作窃取线程池,当前线程池有线程空闲,会自动去寻找任务执行,默认根据CPU核数启动默认线程数目线程,是精灵(demon)线程(守护线程、后台线程),主函数不阻塞的话看不到输出,本质上是ForkJoinPool实现的
6)ForkJoinPool 分叉合并线程,大任务可以切分成许多的小任务,如果小任务还是太大的话还可以继续分,分的可以了就将小任务合并,最后产生一个总的结果(有点像归并排序)
ForkJoinTask从RecursiveAction和RecursiveTask继承
a.RecursiveAction 无返回值
/**
* 对数组中所有数求和
* @author zhangqi
*
*/
public class T12_ForkJoinPool {
static int[] nums = new int[1000000];
static final int MAX_NUM = 50000;
static Random r = new Random(); static {
for(int i=0; i<nums.length; i++) {
nums[i] = r.nextInt(100);
} System.out.println(Arrays.stream(nums).sum()); //stream api
} static class AddTask extends RecursiveAction { int start, end; AddTask(int s, int e) {
start = s;
end = e;
} @Override
protected void compute() { if(end-start <= MAX_NUM) {
long sum = 0L;
for(int i=start; i<end; i++) sum += nums[i];
System.out.println("from:" + start + " to:" + end + " = " + sum);
} else { int middle = start + (end-start)/2; AddTask subTask1 = new AddTask(start, middle);
AddTask subTask2 = new AddTask(middle, end);
subTask1.fork();
subTask2.fork();
} } } /*static class AddTask extends RecursiveTask<Long> { int start, end; AddTask(int s, int e) {
start = s;
end = e;
} @Override
protected Long compute() { if(end-start <= MAX_NUM) {
long sum = 0L;
for(int i=start; i<end; i++) sum += nums[i];
return sum;
} int middle = start + (end-start)/2; AddTask subTask1 = new AddTask(start, middle);
AddTask subTask2 = new AddTask(middle, end);
subTask1.fork();
subTask2.fork(); return subTask1.join() + subTask2.join();
} }*/ public static void main(String[] args) throws IOException {
ForkJoinPool fjp = new ForkJoinPool();
AddTask task = new AddTask(0, nums.length);
fjp.execute(task);
//long result = task.join();
//System.out.println(result); System.in.read(); }
}
运行结果:
b.RescursiveTask 有返回值的递归任务
/**
* 对数组中所有数求和
* @author zhangqi
*
*/
public class T12_ForkJoinPool {
static int[] nums = new int[1000000];
static final int MAX_NUM = 50000;
static Random r = new Random(); static {
for(int i=0; i<nums.length; i++) {
nums[i] = r.nextInt(100);
} System.out.println(Arrays.stream(nums).sum()); //stream api
} /* static class AddTask extends RecursiveAction { int start, end; AddTask(int s, int e) {
start = s;
end = e;
} @Override
protected void compute() { if(end-start <= MAX_NUM) {
long sum = 0L;
for(int i=start; i<end; i++) sum += nums[i];
System.out.println("from:" + start + " to:" + end + " = " + sum);
} else { int middle = start + (end-start)/2; AddTask subTask1 = new AddTask(start, middle);
AddTask subTask2 = new AddTask(middle, end);
subTask1.fork();
subTask2.fork();
} } }*/ static class AddTask extends RecursiveTask<Long> { int start, end; AddTask(int s, int e) {
start = s;
end = e;
} @Override
protected Long compute() { if(end-start <= MAX_NUM) {
long sum = 0L;
for(int i=start; i<end; i++) sum += nums[i];
return sum;
} int middle = start + (end-start)/2; AddTask subTask1 = new AddTask(start, middle);
AddTask subTask2 = new AddTask(middle, end);
subTask1.fork();
subTask2.fork(); return subTask1.join() + subTask2.join();
} } public static void main(String[] args) throws IOException {
ForkJoinPool fjp = new ForkJoinPool();
AddTask task = new AddTask(0, nums.length);
fjp.execute(task);
long result = task.join();
System.out.println(result); //System.in.read(); }
}
运行结果:
补充:
ThreadPoolExecutor线程池执行器(自定义线程池,许多线程池的底层实现,ForkJoinPool不是由它实现)
Java高并发编程(四)的更多相关文章
- [ 高并发]Java高并发编程系列第二篇--线程同步
高并发,听起来高大上的一个词汇,在身处于互联网潮的社会大趋势下,高并发赋予了更多的传奇色彩.首先,我们可以看到很多招聘中,会提到有高并发项目者优先.高并发,意味着,你的前雇主,有很大的业务层面的需求, ...
- java高并发编程(一)
读马士兵java高并发编程,引用他的代码,做个记录. 一.分析下面程序输出: /** * 分析一下这个程序的输出 * @author mashibing */ package yxxy.c_005; ...
- 关于Java高并发编程你需要知道的“升段攻略”
关于Java高并发编程你需要知道的"升段攻略" 基础 Thread对象调用start()方法包含的步骤 通过jvm告诉操作系统创建Thread 操作系统开辟内存并使用Windows ...
- Java高并发编程基础三大利器之CountDownLatch
引言 上一篇文章我们介绍了AQS的信号量Semaphore<Java高并发编程基础三大利器之Semaphore>,接下来应该轮到CountDownLatch了. 什么是CountDownL ...
- java高并发编程(三)
java高并发主要有三块知识点: synchronizer:同步器,在多个线程之间互相之间怎么进行通讯,同步等: 同步容器:jdk提供了同步性的容器,比如concurrentMap,concurren ...
- java高并发编程(四)高并发的一些容器
摘抄自马士兵java并发视频课程: 一.需求背景: 有N张火车票,每张票都有一个编号,同时有10个窗口对外售票, 请写一个模拟程序. 分析下面的程序可能会产生哪些问题?重复销售?超量销售? /** * ...
- java高并发编程(五)线程池
摘自马士兵java并发编程 一.认识Executor.ExecutorService.Callable.Executors /** * 认识Executor */ package yxxy.c_026 ...
- java高并发编程(二)
马士兵java并发编程的代码,照抄过来,做个记录. 一.分析下面面试题 /** * 曾经的面试题:(淘宝?) * 实现一个容器,提供两个方法,add,size * 写两个线程,线程1添加10个元素到容 ...
- java高并发编程基础之AQS
引言 曾经有一道比较比较经典的面试题"你能够说说java的并发包下面有哪些常见的类?"大多数人应该都可以说出 CountDownLatch.CyclicBarrier.Sempah ...
随机推荐
- Spring Boot + Spring Cloud 实现权限管理系统 后端篇(三):搭建开发环境
生成项目模板 登录Spring Initializr生成Spring Boot项目模板,保存到本地. 地址:https://start.spring.io/ 导入Maven项目 使用IDE导入生成的M ...
- SpringCloud入门之eclipse新建maven子项目和聚合项目
一.new maven project : next 二.勾选 create a simple project : next 三.Group Id:项目的包路径 如com.test,之后创建的C ...
- Leetcode 746. Min Cost Climbing Stairs
思路:动态规划. class Solution { //不能对cost数组进行写操作,因为JAVA中参数是引用 public int minCostClimbingStairs(int[] cost) ...
- [开源] .NET数据库ORM类库 Insql
介绍 新年之际,给大家介绍个我自己开发的ORM类库Insql.TA是一个轻量级的.NET ORM类库 . 对象映射基于Dapper , Sql配置灵感来自于Mybatis.简单优雅性能是TA的追求. ...
- Java设计模式学习记录-抽象工厂模式
前言 上篇博客介绍了简单工厂模式和工厂方法模式,这次介绍抽象工厂模式,抽象工厂模式和工厂方法模式的区别在于需要创建对象的复杂程度上. 抽象工厂模式 抽象工厂模式是围绕着一个超级工厂创建其他工厂.这个超 ...
- 【ibatis】IBatis的动态SQL的写法
Ⅰ .动态SQL的写法 开始 <dynamic 条件成立时前面要加的字符串 prepend ="字符串"> prepend="字符串" 判断条件的对 ...
- SpringMVC拦截器和@ResponseBody注解冲突
在使用@ResponseBody注解后controller方法只会返回ModelandView对象的数据模型,不会返回视图,这样有很多好处,但是如果在拦截器中进行了页面转发,在满足页面转发条件时,不会 ...
- 一道很好的mysql面试练习题,having综合应用
写一条SQL语句,求出2门以及2门以上不及格的科目平均分 >要出现2门以及2门以上的学科不及格 >计算该考生所有学科的平均分,不单是,不及格的那几门 #创建表: create table ...
- python乐观锁、悲观锁
二.乐观锁总是认为不会产生并发问题,每次去取数据的时候总认为不会有其他线程对数据进行修改,因此不会上锁,但是在更新时会判断其他线程在这之前有没有对数据进行修改 三.悲观锁总是假设最坏的情况,每次取数据 ...
- 从无到有,用Nodejs+express+mongodb搭建简易登陆系统
前端处理server表示很蛋疼,初学Node,虽然感觉异常强大,但是学起来还是有些吃力的,Node是工具,它不是万能的,搭建一个系统还是需要借助其他一些工具,对于我这个没怎么接触server的前端来说 ...