java并发Executors学习笔记

java并发(1)-Executors
关于java创建多线程常用的两种方式,我就不多说了,无非就是实现Runnable和继承Thread。那么我们现在来说说其他的方法。

Executors是什么
Executors,我们称之为执行器,用于管理Thread对象,简化并发过程,其在客户端和任务执行之间提供了一个间接层。由中介执行任务。无需管理线程的生命周期。
我们先是实现一个Runnable的类,其功能非常简单,就是在一个计数器,而且对于每一个创建的对象来说,其id都不一样,方便我们识别。

class MyCountDownRunnale implements Runnable {
private int countDown = 10;
private static int taskCount = 0;
private final int id = taskCount ++;
public MyCountDownRunnale(){}
public MyCountDownRunnale(int countDown) {
this.countDown = countDown;
}
@Override
public void run() {
while (countDown -- > 0) {
System.out.print(toString());
Thread.yield();//线程都让出使用权,加入竞争。
}
}
@Override
public String toString() {
return "$" + id + "<" + Thread.currentThread().getId() + ">(" + (countDown > 0 ? countDown : "Zero") + "), ";
}
}
CachedThreadPool方式
如下代码:

ExecutorService exec = Executors.newCachedThreadPool();
for (int i = 0; i < 5; i ++) {
exec.execute(new MyCountDownRunnale());
}
exec.shutdown();//防止新线程提交
执行结果:

$1<12>(9), $3<14>(9), $1<12>(8), $2<13>(9), $0<11>(9),
$2<13>(8), $1<12>(7), $3<14>(8), $4<15>(9), $3<14>(7),
$1<12>(6), $2<13>(7), $0<11>(8), $2<13>(6), $1<12>(5),
$3<14>(6), $4<15>(8), $3<14>(5), $1<12>(4), $2<13>(5),
$3<14>(4), $2<13>(4), $0<11>(7), $2<13>(3), $3<14>(3),
$1<12>(3), $4<15>(7), $1<12>(2), $3<14>(2), $2<13>(2),
$0<11>(6), $2<13>(1), $3<14>(1), $2<13>(Zero), $1<12>(1),
$4<15>(6), $1<12>(Zero), $3<14>(Zero), $0<11>(5), $4<15>(5),
$0<11>(4), $4<15>(4), $0<11>(3), $4<15>(3), $0<11>(2),
$4<15>(2), $0<11>(1), $4<15>(1), $0<11>(Zero), $4<15>(Zero),
FixedThreadPool方式
如下代码:

ExecutorService exec =Executors.newFixedThreadPool(4);
for (int i = 0; i < 5; i ++) {
exec.execute(new MyCountDownRunnale());
}
exec.shutdown();//防止新线程提交
执行结果:

$0<11>(9), $3<14>(9), $2<13>(9), $1<12>(9), $2<13>(8),
$3<14>(8), $0<11>(8), $3<14>(7), $0<11>(7), $2<13>(7),
$1<12>(8), $2<13>(6), $0<11>(6), $3<14>(6), $0<11>(5),
$2<13>(5), $1<12>(7), $2<13>(4), $0<11>(4), $3<14>(5),
$0<11>(3), $2<13>(3), $1<12>(6), $2<13>(2), $3<14>(4),
$2<13>(1), $0<11>(2), $1<12>(5), $0<11>(1), $2<13>(Zero),
$3<14>(3), $0<11>(Zero), $1<12>(4), $1<12>(3), $3<14>(2),
$1<12>(2), $4<13>(9), $1<12>(1), $1<12>(Zero), $3<14>(1),
$4<13>(8), $3<14>(Zero), $4<13>(7), $4<13>(6), $4<13>(5),
$4<13>(4), $4<13>(3), $4<13>(2), $4<13>(1), $4<13>(Zero),
SingleThreadExecutor方式
如下代码:

ExecutorService exec = Executors.newSingleThreadExecutor();
for (int i = 0; i < 5; i ++) {
exec.execute(new MyCountDownRunnale());
}
exec.shutdown();//防止新线程提交
执行结果:

$0<11>(9), $0<11>(8), $0<11>(7), $0<11>(6), $0<11>(5),
$0<11>(4), $0<11>(3), $0<11>(2), $0<11>(1), $0<11>(Zero),
$1<11>(9), $1<11>(8), $1<11>(7), $1<11>(6), $1<11>(5),
$1<11>(4), $1<11>(3), $1<11>(2), $1<11>(1), $1<11>(Zero),
$2<11>(9), $2<11>(8), $2<11>(7), $2<11>(6), $2<11>(5),
$2<11>(4), $2<11>(3), $2<11>(2), $2<11>(1), $2<11>(Zero),
$3<11>(9), $3<11>(8), $3<11>(7), $3<11>(6), $3<11>(5),
$3<11>(4), $3<11>(3), $3<11>(2), $3<11>(1), $3<11>(Zero),
$4<11>(9), $4<11>(8), $4<11>(7), $4<11>(6), $4<11>(5),
$4<11>(4), $4<11>(3), $4<11>(2), $4<11>(1), $4<11>(Zero),
三者的区别
看了三个不同的执行结果,我想大家都能知道1和2更3的区别了吧,
1、第三种方式如其名,单线程跑的,他会把提交的任务,按照顺序执行,而且还是在同一个线程里执行的。
2、那第一种和第二种的区别是什么呢?java培训技术构造方法的参数不一样,第二种方式中的参数代表的意思是,一次性预先执行代价昂贵的线程分配,之后就可直接使用了,不过不能滥用,因为数量有限。而第一种就是,执行过程中通常创建所需的数量的线程,然后回收旧线程的时候,停止创建线程。
3、他们两个除了这个区别之外,还有一个重要的特性,就是FixedThreadPool保证了“没有两个线程”会被并发调用。
4、如果一个线程实例请求加入FixedThreadPool时,如果该实例不存在,且没有达到线程池数目上线,则会创建一个实例,否则,会先加入等待序列,当FixedThreadPool中有一个线程停止并移出线程池后,线程实例才能加入线程池。
5、CachedThreadPool中线程实例默认超时时间为60s,超过这个时间,线程实例停止并被移出CachedThreadPool,适用于生存期短、异步的线程任务。FixedThreadPool没有超时机制,适用于稳定且并发线程任务。关于这点,可以看源码中的代码Executors.java:
如下,第三个参数就是超时的时间设置。0就是不超时。

public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}

时间: 2024-10-12 12:23:52

java并发Executors学习笔记的相关文章

Java并发编程学习笔记(一)线程安全性 1

什么是线程安全性: 要编写线程安全的代码,其核心在于要对状态访问操作进行管理,特别是对共享的和可变的状态的访问."共享"意味着变量可以由多个线程同时访问,而"可变"则意味着变量的值在其生命周期内可以发生变化. 一个对象是否需要线程安全的,取决于他是否被多个线程访问.这指的是在程序中访问对象的方式,而不是对象要实现的功能.要使得对象时线程安全的,需要采用同步机制来协同对对象可变状态的访问.如果无法实现协同,那么可能导致数据破坏以及其他不该出现的结果. 如果当多个线程访

Java并发编程学习笔记

Java编程思想,并发编程学习笔记. 一.基本的线程机制 1.定义任务:Runnable接口 线程可以驱动任务,因此需要一种描述任务的方式,这可以由Runnable接口来提供.要想定义任务,只需实现Runnable接口并编写run方法,使得该任务可以执行你的命令.   class MyTask implements Runnable {    private String mName;     public MyTask(String name) {    mName = name;   }  

Java并发编程学习笔记(一)——线程安全性

1.当多个线程访问某个状态变量并且其中有一个献策灰姑娘执行写入操作时,必须采用同步机制来协同这些线程对变量的访问.Java中的主要同步机制是关键字synchronized,他提供了一种独占的加锁方式. 2.在任何情况下,只有当类中仅包含自己的状态时,线程安全类才是有意义的. 3.当多个线程访问某个类时,不管运行时环境采用何种调度方式或者这些献策灰姑娘讲如何交替执行,并且在主调代码中不需要任何额外的同步或协同,这个类都能表现出正确的行为,那么就称这个类是线程安全的. 4.无状态对象一定是线程安全的

JAVA并发编程学习笔记------线程的三种创建方式

创建线程一般有如下几个方式: 1. 通过继承Thread类来创建一个线程: /** * 步骤1:定义一个继承Thread类的子类 * 步骤2:构造子类的一个对象 * 步骤3:启动线程: * */ public class ThreadTest{ public static void main(String[] args) { //构造子类对象 SubThread subThread = new SubThread(); //启动线程 subThread.start(); } } //定义继承Th

JAVA并发编程学习笔记------对象的可见性及发布逸出

一.非原子的64位操作: 当线程在没有同步的情况下读取变量时,可能会得到一个失效值,但至少这个值是由之前某个线程设置的值,而不是一个随机值,这种安全性保证被称为最低安全性.最低安全性适用于绝大多数变量,但存在一个例外:非volatile类型的64位数值变量(double,long),Java内存模型要求,变量的读取和写入操作都必须是原子操作,但对于非volatile型的long,double变量,JVM允许将64位的读操作或写操作分解为两个32位的操作,当读取一个非volatile类型的long

Java并发编程学习笔记(二)——对象的共享

主要概念:可见性.重排序.失效数据.最低安全性.发布.逸出.线程封闭(Ad-hoc.栈封闭.ThreadLocal类).不变性.Final域.事实不可变对象. 1.在没有同步的情况下,编译器.处理器以及运行时等都可能对操作的执行顺序进行一些意想不到的调整.在缺乏足够同步的多线程程序中,要想对内存操作的执行顺序进行判断,几乎无法得出正确的结论. 2.在多线程中使用共享且可变的long和double等类型的变量是不安全的,除非用关键字volatile来声明它们,或者用锁来保护他们. 3.加锁的含义不

JAVA并发编程学习笔记------锁顺序死锁

一.需求描述: 将资金从一个账户转移到另一个账户. 二.程序实现: (1)账户类: public class Account { private long account; public Account(String user, long account) { this.account = account; } public Account() { super(); } public long getAccount() { return account; } public void setAcc

java/android 设计模式学习笔记(16)---命令模式

这篇博客我们来介绍一下命令模式(Command Pattern),它是行为型设计模式之一.命令模式相对于其他的设计模式更为灵活多变,我们接触比较多的命令模式个例无非就是程序菜单命令,如在操作系统中,我们点击关机命令,系统就会执行一系列的操作,如先是暂停处理事件,保存系统的一些配置,然后结束程序进程,最后调用内核命令关闭计算机等,对于这一系列的命令,用户不用去管,用户只需点击系统的关机按钮即可完成如上一系列的命令.而我们的命令模式其实也与之相同,将一系列的方法调用封装,用户只需调用一个方法执行,那

java/android 设计模式学习笔记(14)---外观模式

这篇博客来介绍外观模式(Facade Pattern),外观模式也称为门面模式,它在开发过程中运用频率非常高,尤其是第三方 SDK 基本很大概率都会使用外观模式.通过一个外观类使得整个子系统只有一个统一的高层的接口,这样能够降低用户的使用成本,也对用户屏蔽了很多实现细节.当然,在我们的开发过程中,外观模式也是我们封装 API 的常用手段,例如网络模块.ImageLoader 模块等.其实我们在开发过程中可能已经使用过很多次外观模式,只是没有从理论层面去了解它. 转载请注明出处:http://bl