Java多线程/并发18、Java线程池

来源:互联网 发布:java面试视频 编辑:程序博客网 时间:2024/05/19 06:37

用过数据库的,都了解连接池概念。为了减少建立连接的开销,预先建立好多条连接,由连接池对象统一管理。当有进程需要连接数据库时,就分配一条空闲的连接给它,用完再被收回等待分配给下一个进程使用。
线程池的概念也一样,根据设置预先创建好一些线程,需要时就分配给你,使用完再收回,这样就不用老是去new Thread()了。

Java通过Executors提供四种线程池,分别为:
1、newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
2、newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
3、newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
4、newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

一、newCachedThreadPool 创建可缓存线程池

如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程

public class Executors2 {    public static void main(String[] args) {         ExecutorService threadPool = Executors.newCachedThreadPool();         for(int i=0;i<5;i++){             threadPool.execute(new myRunable());         }    }}class myRunable implements Runnable {    public void run() {        System.out.println(Thread.currentThread().getName() + "执行");    }}

现在newCachedThreadPool创建了5个线程来处理输出任务:

pool-1-thread-1执行pool-1-thread-4执行pool-1-thread-3执行pool-1-thread-2执行pool-1-thread-5执行

现在我们让主线程休眠,放缓往线程池里往任务的节奏看看会是什么结果。修改main函数,让每次放入线程池后都休息一下

public static void main(String[] args) throws InterruptedException {         ExecutorService threadPool = Executors.newCachedThreadPool();         for(int i=0;i<5;i++){             threadPool.execute(new myRunable());             Thread.sleep(1000);         }    }

现在newCachedThreadPool只创建了1个线程来处理输出任务

pool-1-thread-1执行pool-1-thread-1执行pool-1-thread-1执行pool-1-thread-1执行pool-1-thread-1执行

二、newFixedThreadPool 创建定长线程池

public class Executors1 {    public static void main(String[] args) {         ExecutorService threadPool = Executors.newFixedThreadPool(3);         for(int i=0;i<7;i++){             threadPool.execute(new CustomerRunable());         }    }}class CustomerRunable implements Runnable {    public void run() {        System.out.println(Thread.currentThread().getName() + "执行");        try {            Thread.sleep(700);        } catch (InterruptedException e) {            e.printStackTrace();        }    }}

结果:

pool-1-thread-1执行pool-1-thread-3执行pool-1-thread-2执行pool-1-thread-1执行pool-1-thread-3执行pool-1-thread-2执行pool-1-thread-2执行

可以看到,一共有三个线程来执行程序。

三、newScheduledThreadPool 创建定长周期性执行的线程池

该方法最常用的两种用法:
1、schedule(Runnable command,long delay, TimeUnit unit):指定多久之后运行

package JConcurrence.Study;import java.text.SimpleDateFormat;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.TimeUnit;public class Executors2 {    public static void main(String[] args) throws InterruptedException {        ScheduledExecutorService scheduledThreadPool = Executors                .newScheduledThreadPool(5);        for (int i = 0; i < 5; i++) {            scheduledThreadPool.schedule(new myRunable(), 5, TimeUnit.SECONDS);        }        SimpleDateFormat time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");        String TimeString = time.format(new java.util.Date());        System.out.println(Thread.currentThread().getName() + "运行时间是:"+TimeString);    }}class myRunable implements Runnable {    public void run() {        SimpleDateFormat time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");        String TimeString = time.format(new java.util.Date());        System.out.println(Thread.currentThread().getName() + "运行时间是:"+TimeString);    }}

输出

main运行时间是:2009-12-21 21:59:34pool-1-thread-1运行时间是:2009-12-21 21:59:39pool-1-thread-1运行时间是:2009-12-21 21:59:39pool-1-thread-1运行时间是:2009-12-21 21:59:39pool-1-thread-1运行时间是:2009-12-21 21:59:39pool-1-thread-1运行时间是:2009-12-21 21:59:39

2、scheduleAtFixedRate(Runnable command ,long initialDelay,long period, TimeUnit unit):指定多久之后以什么频率运行
把刚刚那一段中的

scheduledThreadPool.schedule(new myRunable(), 5, TimeUnit.SECONDS);

替换为

scheduledThreadPool.scheduleAtFixedRate(new myRunable(), 5,2, TimeUnit.SECONDS);

运行看看结果,可以发现源源不断的每隔2秒输出一次。

四、newSingleThreadExecutor 创建一个单线程化的线程池

用法和newCachedThreadPool没什么太大区别,只不过它只创建一个线程。
用它创建的线程池始终能保持一个存活的线程,如果该线程死了,也会重新生成一个
而自己new Thread出来的线程,如果挂了,就没有然后了。
代码和newCachedThreadPool类似,只是效果不同。不再举例。

五、配合ThreadFactory接口的使用

六、线程池中shutdown和shutdownNow的区别

shutDown()
当线程池调用该方法时,线程池的状态则立刻变成SHUTDOWN状态。此时,则不能再往线程池中添加任何任务,否则将会抛出RejectedExecutionException异常。但是,此时线程池不会立刻退出,直到添加到线程池中的任务都已经处理完成,才会退出。

shutdownNow()
根据JDK文档描述,大致意思是:执行该方法,线程池的状态立刻变成STOP状态,并试图停止所有正在执行的线程,不再处理还在池队列中等待的任务,当然,它会返回那些未执行的任务。
它试图终止线程的方法是通过调用Thread.interrupt()方法来实现的,但是大家知道,这种方法的作用有限,如果线程中没有sleep 、wait、Condition、定时锁等应用, interrupt()方法是无法中断当前的线程的。所以,ShutdownNow()并不代表线程池就一定立即就能退出,它可能必须要等待所有正在执行的任务都执行完成了才能退出。

0 0