JDK并发包中的线程池(一)

不使用线程池时的一些问题

public class NonePool {
    public static void main(String[] args) {
        new Thread(){
            public void run() {
                //TODO
            };
        }.start();
    }
}

上面的代码新建了一个线程,在线程结束的时候,线程会自动被回收
在生产环境中可能需要创建若干个线程来完成系统的功能,当需要的线程数量很多的时候就会需要分配大量的线程,此时还是使用这种方法就会有以下问题:
1. 创建大量的线程需要消耗大量的内存个CPU
2. 线程本身也需要占据大量的内存和CPU
3. 线程执行完后需要回收,回收的时候需要大量的GC操作
综上,在系统中,线程的数量并不是越多就越会提升系统的性能,需要有一个限度

线程池

为了避免频繁的创建线程和销毁线程,我们可以让创建的线程进行复用,类似于数据库连接池。

JDK中支持的线程池

  1. public static ExecutorService newFixedThreadPool(int nThreads)
    含有固定数量为nThreads的线程的线程池,提交任务的时候,如果有线程则立即执行,没有的话则先将任务暂存在一个任务队列中
  2. public static ExecutorService newSingleThreadExecutor()
    只有一个线程的线程池,若有多余的任务被提交,那么先将任务保存在一个队列中,待线程空闲,按照FIFO的策略执行下一个线程
  3. public static ExecutorService newCachedThreadPool()
    返回一个可以根据实际情况调整线程数量的线程池。线程池的数量是不确定的,有空闲线程可以复用的话,那么就优先使用这些线程。如果没有空闲的线程,那么会创建新的线程处理任务,线程执行完毕后,将返回线程池进行服用,默认的情况下如果一个线程超过60秒没有被使用,那么就会被回收
  4. public static ScheduledExecutorService newSingleThreadScheduledExecutor()
    线程池中线程的数量为1,不过返回的是ScheduledExecutorService对象,意味着可以在指定的时间执行任务
    5.public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
    类似于第四种,不过可以指定线程中线程的数量

线程池案例分析

newFixedThreadPool

public class FixedThreadPool {
    public static void main(String[] args) {
        ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
        for(int i=0;i<10;i++){
            fixedThreadPool.submit(new MyTask(i));
        }
    }
}

class MyTask implements Runnable{
    private int i;
    public MyTask(int i) {
        super();
        this.i = i;
    }
    @Override
    public void run() {
        System.out.println(new Date().getTime()+"___"+Thread.currentThread().getId()+"___"+i);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
1497167121692___13___4
1497167121692___10___1
1497167121692___11___2
1497167121692___12___3
1497167121692___9___0
1497167122692___13___5
1497167122692___9___6
1497167122693___10___7
1497167122694___11___8
1497167122694___12___9

分析:
可以看出第一批执行的时间是1497167121692,第二批的五个是1497167122692,并且前5个的执行的线程的id与后5个是一样的,证明的确创建了5个线程,并且可以被复用

newScheduledThreadPool

scheduleAtFixedRate
public class ScheduledThreadPool {
    public static void main(String[] args) {
        ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10);
        scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
System.out.println(Thread.currentThread().getId()+"\tbegin\t"+System.currentTimeMillis());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getId()+"\tend\t"+System.currentTimeMillis());
            }
        }, 0, 2, TimeUnit.SECONDS);
    }
}

public ScheduledFuture

9   begin   1497178292150
9   end     1497178293151
9   begin   1497178294151
9   end     1497178295152
11  begin   1497178296151
11  end     1497178297151
9   begin   1497178298151
9   end     1497178299151

注意
如果每个任务需要耗费的时间大于period,怎么办?
将上面的任务的休眠1s改为休眠8s,结果如下:

9   begin   1497178511226
9   end     1497178519227
9   begin   1497178519227
9   end     1497178527228
11  begin   1497178527229
11  end     1497178535229
9   begin   1497178535229
9   end 1497178543229

可以看出此时执行后续第一个任务(第一次执行不算)的时间是initialDelay+8s,执行后续第二个任务的时间是initialDelay+2*8s,也就是说在同一时刻只会有一个任务在实行,并且执行的周期为任务需要花费的时间与周期的大小之间去大值

scheduleWithFixedDelay

同样的上面的代码,如果将scheduledAtFixedRate改成scheduleWithFixedDelay,就会变成后续的任务会在前面的任务执行完毕后period时间执行,上面程序的运行结果就是

9   begin   1497178896324
9   end     1497178897324
9   begin   1497178899324
9   end     1497178900325
11  begin   1497178902326
11  end     1497178903326
9   begin   1497178905327
9   end     1497178906327

可以看出每一个任务的开始都是在上一个任务结束就的2秒钟才执行的

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值