JAVA多线程之——常用线程池

30 篇文章 0 订阅

线程池

学习了线程池的基本原理后,可以理解线程池的类型控制,主要是通过中心池大小,和最大线程池大小,以及存储工作任务的队列决定。JDK中为我们封装了常用的四种线程池。
在JDK帮助文档中,有如此一段话:
“强烈建议程序员使用较为方便的Executors工厂方法Executors.newCachedThreadPool()(无界线程池,可以进行自动线程回收)、Executors.newFixedThreadPool(int)(固定大小线程池)Executors.newSingleThreadExecutor()(单个后台线程)。
学习常用线程池,关键点就在于理解线程池大小与各种队列的搭配。
回顾线程吃的基本工作流程
如果运行的线程少于 corePoolSize,则 Executor始终首选添加新的线程,而不进行排队。(如果当前运行的线程小于corePoolSize,则任务根本不会存放,添加到queue中,而是直接抄家伙(thread)开始运行)
如果运行的线程等于或多于 corePoolSize,则 Executor始终首选将请求加入队列,而不添加新的线程。
如果无法将请求加入队列,则创建新的线程,除非创建此线程超出 maximumPoolSize,在这种情况下,任务将被拒绝。
newCachedThreadPool

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

此线程池通过设置maximumPoolSize为最大整型值,SynchronousQueue是一个无界队列,这样就可以无限创建线程,通过设置线程空闲keepAliveTime 时间为60秒,这就达到一个缓存的效果。使用SynchronousQueue队列,基于它的另外一个特性,该队列每次只能有一个元素,这样,当队列中有一个元素在等待的时候,后续的新的任务,无法加入队列,就可以直接通过创建新的线程进行运行,不需要在队列中等待执行。

public class ThreadPoolExecutorTest {

  public static void main(String[] args) {
Executors.newSingleThreadExecutor();
ExecutorService pool = Executors.newCachedThreadPool();
List<Mycommand>  commands = new ArrayList<Mycommand>();
Mycommand command = null;
for(int i = 0; i < 10; i++) {
    command = new Mycommand();
    commands.add(command);
}

for(Mycommand myommand : commands) {
    pool.execute(myommand);
}



}

  static  class Mycommand  implements Runnable{
@Override
public void run() {
        System.out.println("Mycommand-" + Thread.currentThread().getName() +  "我执行拉。。。");
}
}

执行结果:

Mycommand-pool-2-thread-1我执行拉。。。
Mycommand-pool-2-thread-2我执行拉。。。
Mycommand-pool-2-thread-1我执行拉。。。
Mycommand-pool-2-thread-3我执行拉。。。
Mycommand-pool-2-thread-3我执行拉。。。
Mycommand-pool-2-thread-1我执行拉。。。
Mycommand-pool-2-thread-4我执行拉。。。
Mycommand-pool-2-thread-7我执行拉。。。
Mycommand-pool-2-thread-6我执行拉。。。
Mycommand-pool-2-thread-5我执行拉。。。

结果可以看到,其中有多个thread-1在运行,这说明线程是被重用了。缓存线程池,使用于处理速度大于线程提交速度。因为它是无界的,也就是说无限大,如果提交速度大于处理速度,那么就会一直创造线程,可能造成资源耗尽。
newSingleThreadExecutor

public class ThreadPoolExecutorTest {
     static AtomicInteger index = new AtomicInteger(0);
       public static void main(String[] args) {
        ExecutorService pool = Executors.newSingleThreadExecutor();
        List<Mycommand>  commands = new ArrayList<Mycommand>();
        Mycommand command = null;
        for(int i = 0; i < 10; i++) {
            command = new Mycommand();
            commands.add(command);
        }
        for(Mycommand myommand : commands) {
            pool.execute(myommand);
        }
    }

       static  class Mycommand  implements Runnable{
        @Override
        public void run() {

                System.out.println("Mycommand-" + index.getAndIncrement() + "-" + Thread.currentThread().getName() +  "我执行拉。。。");
        } 
       }  
}

运行结果:

Mycommand-0-pool-1-thread-1我执行拉。。。
Mycommand-1-pool-1-thread-1我执行拉。。。
Mycommand-2-pool-1-thread-1我执行拉。。。
Mycommand-3-pool-1-thread-1我执行拉。。。
Mycommand-4-pool-1-thread-1我执行拉。。。
Mycommand-5-pool-1-thread-1我执行拉。。。
Mycommand-6-pool-1-thread-1我执行拉。。。
Mycommand-7-pool-1-thread-1我执行拉。。。
Mycommand-8-pool-1-thread-1我执行拉。。。
Mycommand-9-pool-1-thread-1我执行拉。。。

newFixedThreadPool

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

理解了单一线程池,那么固定大小的线程池就不难理解了,只需要修改corePoolSize与maximumPoolSize的大小并且保证相等就可以了。但一线程池就是一个大小为1的固定线程池。

public class ThreadPoolExecutorTest {
     static AtomicInteger index = new AtomicInteger(0);
       public static void main(String[] args) {
        ExecutorService pool = Executors.newFixedThreadPool(2);
        List<Mycommand>  commands = new ArrayList<Mycommand>();
        Mycommand command = null;
        for(int i = 0; i < 10; i++) {
            command = new Mycommand();
            commands.add(command);
        }
        for(Mycommand myommand : commands) {
            pool.execute(myommand);
        }
    }

       static  class Mycommand  implements Runnable{
        @Override
        public void run() {

                System.out.println("Mycommand-" + index.getAndIncrement() + "-" + Thread.currentThread().getName() +  "我执行拉。。。");
        } 
       }  
}

某次运行结果:

Mycommand-0-pool-1-thread-1我执行拉。。。
Mycommand-1-pool-1-thread-2我执行拉。。。
Mycommand-2-pool-1-thread-1我执行拉。。。
Mycommand-3-pool-1-thread-2我执行拉。。。
Mycommand-4-pool-1-thread-1我执行拉。。。
Mycommand-5-pool-1-thread-2我执行拉。。。
Mycommand-6-pool-1-thread-1我执行拉。。。
Mycommand-8-pool-1-thread-1我执行拉。。。
Mycommand-7-pool-1-thread-2我执行拉。。。
Mycommand-9-pool-1-thread-1我执行拉。。。

newScheduledThreadPool

public ScheduledThreadPoolExecutor(int corePoolSize) {
      super(corePoolSize, Integer.MAX_VALUE, 0, TimeUnit.NANOSECONDS,
            new DelayedWorkQueue());
  }

延迟线程池,都了解过JAVA的timer。这个就是一个优化的延迟执行的线程池。一般用于定时任务。

public class ThreadPoolExecutorTest {
     static AtomicInteger index = new AtomicInteger(0);
       public static void main(String[] args) {
           ScheduledExecutorService  pool = Executors.newScheduledThreadPool(1);
        List<Mycommand>  commands = new ArrayList<Mycommand>();
        Mycommand command = new Mycommand();

            pool.scheduleAtFixedRate(command, 1000, 2000, TimeUnit.MILLISECONDS);
    }

       static  class Mycommand  implements Runnable{
        @Override
        public void run() {
                System.out.println(System.currentTimeMillis());
                System.out.println("Mycommand-" + index.getAndIncrement() + "-" + Thread.currentThread().getName() +  "我执行拉。。。");
        } 
       }  
}

运行结果:

1491629176413
Mycommand-0-pool-1-thread-1我执行拉。。。
1491629178413
Mycommand-1-pool-1-thread-1我执行拉。。。
1491629180413
Mycommand-2-pool-1-thread-1我执行拉。。。
1491629182414
Mycommand-3-pool-1-thread-1我执行拉。。。
1491629184414
Mycommand-4-pool-1-thread-1我执行拉。。。
1491629186414
Mycommand-5-pool-1-thread-1我执行拉。。。
1491629188414
Mycommand-6-pool-1-thread-1我执行拉。。。
1491629190414
Mycommand-7-pool-1-thread-1我执行拉。。。
1491629192414
Mycommand-8-pool-1-thread-1我执行拉。。。

传统的timer的缺点:Timer对任务的调度是基于绝对时间的;所有的TimerTask只有一个线程TimerThread来执行,因此同一时刻只有一个TimerTask在执行;任何一个TimerTask的执行异常都会导致Timer终止所有任务;由于基于绝对时间并且是单线程执行,因此在多个任务调度时,长时间执行的任务被执行后有可能导致短时间任务快速在短时间内被执行多次或者干脆丢弃多个任务。
newScheduledThreadPool功能比Timer更加强大,性能也更加好。这里至列举了其中的一个方法。具体可以参照API进行配置运行。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值