java提高班 -- java多线程(3)线程池

本文版权归作者所有,转载请标明出处。未与作者联系不得用于任何商业用途

2011年5月18日

关新全

山东东营 石油大学

2.3 线程池

       创建线程是需要一定的代价的,因此,在一个应用程序中创建过多的线程会占用大量系统资源,降低程序的执行速度,甚至造成java虚拟机的崩溃。使用线程池主要出于两种目的,首先,一个线程池会维护一定数量的线程,当新的多线程任务到来后,线程池会寻求一个空闲线程执行任务,如果线程池中没有可用的空闲线程,那么线程池等待(不同线程池的动作不同)直至有新的空闲线程的产生,如果线程池中的某个线程执行结束,那么这个线程不会立即销毁退出,它会作为一个空闲线程放入线程池中,以便执行其他的线程任务。其次,使用线程池可以减少系统内并发线程的数目,防止系统因创建过多线程而导致的性能下降或崩溃。一般情况下,系统中存在大量的生命期较短的线程,应当使用线程池。

2.3.1 创建线程池

       线程池的创建需要调用Executor的一些静态工厂方法。Executor的newCachedThreadPool可用创建一个缓冲的线程池,此类线程池,在系统需要的时候会创建新线程,空闲线程等待指定时间后仍未被使用将会被释放(具体开启多少线程,由系统决定)。newFixedThreadPool用来创建一个指定大小的线程池。newSingleThreadExecutor用来生成单一线程的线程池,这个线程池会按照顺序一个接一个的执行线程任务。newScheduleThreadPool用于执行固定频率的线程任务(替代Timer)。newSingleThreadScheduleExecutor用来创建固定频率任务的单线程线程池。

       在线程池创建后,任务执行完成后使用shutDown方法释放线程池资源。

       Demo2-9将从0-99求和的程序使用了线程池的方法进行了修改。在主线程中创建了线程池,然后将计算任务分发到下面的子线程,最后主线程统计计算任务输出结果。在这个过程中每个子线程都输出了自己线程的名字,可以便于我们观察到底是哪个线程执行了当前线程任务,从结果中不难看出,很多线程执行了多个任务。此外,调用线程池的shutDown方法,并不会造成阻塞,在主线程中需要设置专门的同步策略(这里用的是CountDownLatch)来等待所有子线程结束。当线程池调用shutDown方法后,线程池并不会立即关闭,而是在线程池没有任务执行的情况下才关闭管辖的所有线程,可以通过调用shutDownNow方法即时关闭线程池。此外ThreadPoolExecutor类可以包装一个ExecutorServer类,并提供了一些对线程池的附加操作(他们之间的关系同Thread与FutureTask的关系相似),可以查阅java API获取更多的知识。

Demo2-9 线程池示例

package com.upc.upcgrid.guan.advancedJava.chapter02;

 

import java.util.ArrayList;

import java.util.List;

import java.util.concurrent.CountDownLatch;

import java.util.concurrent.ExecutorService;

import java.util.concurrent.Executors;

import java.util.concurrent.ThreadPoolExecutor;

 

class OnceComputePool implements Runnable{

    private int begin;

    private int end;

    private CountDownLatch latch;

    private int sum = 0;

    public OnceComputePool(int begin,int end) {

       this.begin = begin;

       this.end = end;     

    }

   

    public OnceComputePool(int begin, int end, CountDownLatch latch) {

       this.begin = begin;

       this.end = end;

       this.latch = latch;

      

    }

 

    @Override

    public void run() {

       for(int i = begin; i < end ; i++)

           sum += i;

       System.err.println(Thread.currentThread().getName());

       latch.countDown();

    }

   

    public int getSum()

    {

       return sum;

    }

}

public class ThreadPool {  

    public static void main(String[] args) throws InterruptedException {

       final int MAX_THREAD_SIZE = 10;

       ExecutorService pool = Executors.newCachedThreadPool();

       CountDownLatch latch = new CountDownLatch(MAX_THREAD_SIZE);

       List<OnceComputePool> tasks = new ArrayList<OnceComputePool>();

      

       int sum = 0;

      

       for(int i = 0 ;i < MAX_THREAD_SIZE ;i++)

       

           OnceComputePool task = new OnceComputePool(i*10, (i+1)*10,latch);

           tasks.add(task);

           pool.submit(task);         

       }

       pool.shutdown();

       System.err.println(Thread.currentThread().getName());

       latch.await();

       for(OnceComputePool task: tasks)

           sum += task.getSum();

       System.err.println(sum);

       System.err.println(((ThreadPoolExecutor) pool).getLargestPoolSize());

    }

   

}

Demo2-9 的执行结果

pool-1-thread-1

pool-1-thread-1

pool-1-thread-1

pool-1-thread-3

main

pool-1-thread-2

pool-1-thread-5

pool-1-thread-4

pool-1-thread-7

pool-1-thread-6

4950

7

2.3.2 使用线程池执行定期任务

       ScheduleExecutorServer接口可以用来执行预定义任务。使用Executors类的newScheduledThreadPool和newSingleThreadSchedulePool可以获得实现了ScheduleExecutorServer接口的对象。

       ScheduleExecutorServer类中的schedule方法将在指定时间后执行某一任务,scheduleAtFixedRate方法用来执行周期性任务。Demo2-10给出了一个调度线程池的例子,这个例子每隔1s钟就执行一次输出当前时间的操作。定时的线程池可以作为Timer的替代方案,Demo2-11给出了使用Timer实现的相同功能的定时任务。

 

Demo2-10 定期执行任务

package com.upc.upcgrid.guan.advancedJava.chapter02;

 

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.concurrent.Executors;

import java.util.concurrent.ScheduledExecutorService;

import java.util.concurrent.TimeUnit;

 

public class SchedulePool {

    public static void main(String[] args) throws InterruptedException {

       ScheduledExecutorService timer = Executors.newSingleThreadScheduledExecutor();

       timer.scheduleAtFixedRate(new Runnable() {

           SimpleDateFormat formate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

           @Override

           public void run() {

              System.out.println(formate.format(new Date()));

           }

       }, 100,1000,TimeUnit.MILLISECONDS);

       Thread.sleep(5000);

       timer.shutdown();

    }

}

Demo2-11 执行结果

2011-05-18 10:24:40

2011-05-18 10:24:41

2011-05-18 10:24:42

2011-05-18 10:24:43

2011-05-18 10:24:44

Demo2-11 使用Timer完成同样定时功能

package com.upc.upcgrid.guan.advancedJava.chapter02;

 

import java.text.SimpleDateFormat;

import java.util.Date;

import java.util.Timer;

import java.util.TimerTask;

 

public class ScheduleTimer {

    public static void main(String[] args) throws InterruptedException {

       Timer timer = new Timer ();

       timer.schedule(new TimerTask() {

           SimpleDateFormat formate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

           @Override

           public void run() {

              System.out.println(formate.format(new Date()));

           }

       },100, 1000);

      

       Thread.sleep(5000);

       timer.cancel();

    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值