引入:

在之前的例子中,我们需要使用线程时就直接去创建一个线程,这样既不浪费资源又十分方便。但如果我们需要创建多个并发的线程,而且短时间执行就结束了,如果还用之前的方式,就会大大降低效率和性能了。

因此就引入了线程池。

在java线程池中,涉及到的有Executors、Executor、ExecutorService等,Executor接口表示线程池,ExecutorService负责管理线程池,Executors负责创建生成ExecutorService的实例,提供了线程池的简单实现。他们相互之间的关系如下:

1、Executor

public interface Executor {
void execute(Runnable command);
}

在上面的例子中,我们就调用了execute()方法。execute()方法用来执行Runnable类型的任务,它的子接口是ExecutorService。

ExecutorService负责管理线程池,提供了包括关闭、提交等一系列的操作。

public interface ExecutorService extends Executor {

    void shutdown();

    List<Runnable> shutdownNow();

    boolean isShutdown();

    boolean isTerminated();

 //提交
<T> Future<T> submit(Callable<T> task); <T> Future<T> submit(Runnable task, T result); Future<?> submit(Runnable task); ...... }

2、Executors

Executors类负责生成各种类型的线程池的实例,但主要有三种:固定线程池、可变和单任务线程池。其他详细的方法可参见下面:

public class Executors {

//1、固定大小线程池
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
} //2、可变尺寸线程池
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
} //3、单任务线程池
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
} //4、延迟连接池
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
} //5、单任务延迟连接池
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1));
}
}

我们先通过简单的例子看一下这三种线程池的不同。

1)固定线程池

public static void main(String[] args) {
// 固定线程池:创建一个线程池,有三个线程
ExecutorService threadPool = Executors.newFixedThreadPool(3); for (int i = 1; i <= 10; i++) {
final int task = i;
threadPool.execute(new Runnable() { @Override
public void run() { try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "=====" + "for task of" + task); }
});
}
System.out.println("all task have committed"); }

执行结果:

2)缓存(不固定)线程池

 ExecutorService threadPool=Executors.newCachedThreadPool();

修改一行代码,创建缓存可变长的线程池。执行结果为

3)单任务线程池

ExecutorService threadPool = Executors.newSingleThreadExecutor();

在该线程池中只有一个线程执行。虽然看起来跟单线程没什么区别,但他的优点是,有替补线程可以随时补上。如果该单线程出现问题,立马就会有一个线程继续执行,安全性大大提高。执行结果如下:

4)延迟连接池

// 启动定时器
Executors.newScheduledThreadPool(3).scheduleAtFixedRate(new Runnable() { @Override
public void run() { System.out.println("booming__________"
+ getTime()); }
}, 3, 2, TimeUnit.SECONDS);

其中scheduleAtFixedRate方法参数:

ScheduledFuture<?> java.util.concurrent.ScheduledExecutorService.scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)

时间单位为秒,初始延迟为3秒,每隔2秒执行一次。执行结果为:

使用:

1)直接使用Executors

上面的例子都是直接通过调用Executors中的静态方法实现创建线程池的,很容易理解。

再看一下具体是如何创建线程池的,以其中一种为例:

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

在ThreadPoolExecutor中,需要传入参数Executors.defaultThreadFactory(),他是默认的线程工厂。

 public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}

DefaultThreadFactory依旧在Executors类中。

/**
* The default thread factory默认线程工厂
*/
static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger poolNumber = new AtomicInteger(1);
//线程组
private final ThreadGroup group;
private final AtomicInteger threadNumber = new AtomicInteger(1);
private final String namePrefix; //构造方法
DefaultThreadFactory() {
SecurityManager s = System.getSecurityManager();
group = (s != null) ? s.getThreadGroup() :
Thread.currentThread().getThreadGroup(); //拼接线程名称:如"pool-1-thread-1"
namePrefix = "pool-" +
poolNumber.getAndIncrement() +
"-thread-";
}
//重写newThread方法
public Thread newThread(Runnable r) {
Thread t = new Thread(group, r,
namePrefix + threadNumber.getAndIncrement(),
0);
//如果是守护进程,置为false
if (t.isDaemon())
t.setDaemon(false);
//设置默认优先级
if (t.getPriority() != Thread.NORM_PRIORITY)
t.setPriority(Thread.NORM_PRIORITY);
return t;
}
}

在创建线程池之后,返回的threadpool只有部分参数信息,包括最大线程数、线程名称等,此时只有main主线程。

当执行threadPool.execute()时,会调用上述的默认线程工厂中的newThread方法,创建线程。

 2)直接使用ThreadPoolExecutor类创建

这种方式并不推荐使用,因为对于开发者来说比较困难,也不好管理和维护。但这种方式可以做到对线程池更细致更自由化的控制。

这块内容是线程创建的核心,我们下篇继续介绍。

java线程(5)——线程池(上)的更多相关文章

  1. Java并发:搞定线程池(上)

    原文地址:https://www.nowcoder.com/discuss/152050?type=0&order=0&pos=6&page=0 本文是在原文的基础+理解,想要 ...

  2. java 多线程 4 线程池

    系统启动一个新线程的成本是比较高的,因为它涉及到与操作系统的交互.在这种情况下,使用线程池可以很好的提供性能,尤其是当程序中需要创建大量生存期很短暂的线程时,更应该考虑使用线程池. 与数据库连接池类似 ...

  3. (转)java自带线程池和队列详细讲解 - CSDN过天的专栏

    一简介 线程的使用在java中占有极其重要的地位,在jdk1.4极其之前的jdk版本中,关于线程池的使用是极其简陋的.在jdk1.5之后这一情况有了很大的改观.Jdk1.5之后加入了java.util ...

  4. Java 四种线程池newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor

    介绍new Thread的弊端及Java四种线程池的使用,对Android同样适用.本文是基础篇,后面会分享下线程池一些高级功能. 1.new Thread的弊端执行一个异步任务你还只是如下new T ...

  5. Java四种线程池

    Java四种线程池newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor 时间:20 ...

  6. java自带线程池和队列详细讲解

    Java线程池使用说明 一简介 线程的使用在java中占有极其重要的地位,在jdk1.4极其之前的jdk版本中,关于线程池的使用是极其简陋的.在jdk1.5之后这一情况有了很大的改观.Jdk1.5之后 ...

  7. Java四种线程池newCachedThreadPool,newFixedThreadPool,newScheduledThreadPool,newSingleThreadExecutor

    1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? Java new Thread(new Runnable() { @Override public void ru ...

  8. Java多线程之线程池

    现在是多核的时代,面向多核的编程很重要,因此基于java的并发和多线程开发非常重要. 线程池是于队列密切相关的,其中队列保存了所有等待执行的任务.工作者线程的任务很简单:从队列中获取一个任务,执行任务 ...

  9. Java多线程和线程池

    转自:http://blog.csdn.net/u013142781/article/details/51387749 1.为什么要使用线程池 在Java中,如果每个请求到达就创建一个新线程,开销是相 ...

  10. Java 四种线程池的用法分析

    1.new Thread的弊端 执行一个异步任务你还只是如下new Thread吗? new Thread(new Runnable() { @Override public void run() { ...

随机推荐

  1. Linux的开山篇

    一.Linux的学习方向 1.2Linux运维工程师 1.2.2Linux嵌入式开发工程师 1.2.3在Linux下做各种程序开发    javaEE   大数据    Python  PHP  C/ ...

  2. 台式机上如何配置并使用苹果iPhone的耳机麦克风 并且麦克风开启降噪功能

    这个资料和技巧在网络上面很少有人分享,但是可能会有不少人需要这个东西.这里分享下经验.这也是一个困扰我很久的一个问题.因为买来了这个转接头,发现,录音的时候iPhone的耳机麦克风有很大的噪音无法消除 ...

  3. jquery图片滚动animate.css

    @charset "UTF-8"; /*!Animate.css - http://daneden.me/animateLicensed under the MIT license ...

  4. android SearchView和ListView简单使用

    其实我写代码最担心遇到关于适配器的使用,在我的感觉中适配器是个难度很大的知识点,但是不能因为难而不去学习啊,毕竟现在时间很充裕,可以慢慢学,所以,不会也要写,真所谓,迎难而上啊.  下面是Search ...

  5. Cacti 学习笔记

    Cacti是用php语言实现的一个软件,它的主要功能是用snmp服务获取数据,然后用rrdtool储存和更新数据,当用户需要查看数据的时候用rrdtool生成图表呈现给用户.因此,snmp和rrdto ...

  6. node.js中http通讯模块

    创建一个服务器 首先建立一个js文件,命名为app.js写入内容: const http=require('http'); http.createServer((request,response)=& ...

  7. 微信小程序 - 生命周期 - 参数传递

    ​ 现在WEB开发门槛越来越高,不想java 会了就可以有工作,前端不行 ,不仅JavaScript要求不低,基础的HTML+CSS还要扎实,jquery也是必须要会,现在的前端框架 Vue Ng R ...

  8. http状态码(status_codes)

    首先:1XX 接受的请求正在处理,2XX请求正常处理完毕,3XX需要进行附加操作以完成请求(重定向?),4XX服务器无法处理请求(也就是客户端请求错误),5XX服务器处理请求出错. 当然不仅仅是一张图 ...

  9. Laravel5.x 封装的上传图片类

    图片缩放需要用conposer安装 ImageManagerStatic类 可参考下面的地址安装: https://www.jb51.net/article/128159.htm 控制器里: 控制器里 ...

  10. Java --本地提交MapReduce作业至集群☞实现 Word Count

    还是那句话,看别人写的的总是觉得心累,代码一贴,一打包,扔到Hadoop上跑一遍就完事了????写个测试样例程序(MapReduce中的Hello World)还要这么麻烦!!!?,还本地打Jar包, ...