Java线程池的简单使用

最近在写代码的时候需要模拟多个用户并发请求的场景,这种时候借助于多线程来实现是个很好的办法。而利用线程池来管理和实现多线程是目前比较流行和高效的做法了。

什么是线程池?

我的理解是,线程池就像一个池子,里面有好多的线程。当我们有任务要执行的时候,就从池子里面拿出一个线程来执行,执行完毕之后就把线程放回到池子里。当然如果此时池子里没有线程,那就要等待了。

为什么要用线程池?

通过上面的描述,其实很容易得出使用线程池的好处,主要有三点:第一,降低系统消耗,线程可以重复使用,避免资源反复创建销毁。第二,减少任务等待,线程池中的线程是已经创建好的,任务创建后直接就可以支持,减少了等待线程创建的时间。第三,提高线程可管理性,因为线程都在一个池子里,可以统一的进行分配,监控,管理等。

怎么使用?

说了线程池的好,那就要说说具体该怎么使用了。Java提供了Executors类来创建线程池。能够创建线程池主要有以下几种:

  1. newFixedThreadPool,创建指定线程个数的线程池,也就是说如果任务数比线程数多了,那任务就只能在一个队列中排队等候了。
  2. newSingleThreadExecutor,顾名思义就是创建单个线程,所有的任务按照FIFO的顺序执行。
  3. newCachedThreadPool,这是创建一个可以动态变化大小的线程池,这个就比较智能的感觉,当线程池中线程不够用的时候可以主动创建线程,然后当线程空闲一段时间后,可以主动回收线程。
  4. newScheduledThreadPool,创建一个周期执行任务的线程池。
  5. newWorkStealingPool,JAVA 8中新加的一种,它创建和当前机器可用处理器个数等量的线程数。

实际编码中,大同小异这里以newFixedThreadPool为例,示例代码如下:

先创建一个Runable类说明线程执行的任务内容:

static class Work implements Runnable {
private int workNumber;

    public Work (int n) {
        this.workNumber = n;
    }

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() +
        " Start, " + "Work Number: " + this.workNumber);
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() +
                " Done, " + "Work Number: " + this.workNumber);

    }
}</pre>

 

再创建线程池来执行任务:

 public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(4);
for (int i = 0; i < 10; i++) {
executor.execute(new Work(i));
}

    executor.shutdown();
    try {
        executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.println("All done.");
}</pre>

 

需要注意的就是在提交完任务给线程池后,如果想要等所有线程都执行完就要先调用shutdown(),再调用awaitTermination()即可。

下面就是程序运行的结果:

java thread pool result

OK,对于线程池的简单使用到这里就可以了。当然根据需求的不同可以对线程池做各种定制修改,可以参考官方文档。这里就不多说了,看以后有没有机会碰到吧。