概念

线程:有时被称为轻量级进程 (Lightweight Process,LWP),是程序执行流的最小单元。
多线程:(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。
线程池:是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。

创建线程

package com.carl.threaddemo;

public class ThreadIm1 {

    public static void main(String[] args) {
        new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("ThreadIm1");
            }

        }).start();
        System.out.println("end");
    }
}
package com.carl.threaddemo;

public class ThreadIm2 implements Runnable {

    @Override
    public void run() {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("ThreadIm2");
    }

    public static void main(String[] args) {
        Thread t = new Thread(new ThreadIm2());
        t.start();;
        System.out.println("end");
    }


}

线程池

由于线程是系统中的资源,频繁创建和销毁将带来性能上的开销,所以引入了线程池,

优点

一来避免线程间抢占系统资源导致的阻塞,
二来提高了线程的利用率,
三来可对线程进行管理并提供定时执行等功能

创建线程池的常用方法

1)newCachedThreadPool 是一个可根据需要创建新线程的线程池,但是在以前构造的线程可用时将重用它们。对于执行很多短期异步任务的程序而言,这些线程池通常可提高程序性能。调用 execute() 将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有 60 秒钟未被使用的线程。因此,长时间保持空闲的线程池不会使用任何资源。注意,可以使用 ThreadPoolExecutor 构造方法创建具有类似属性但细节不同(例如超时参数)的线程池。

2)newSingleThreadExecutor 创建是一个单线程池,也就是该线程池只有一个线程在工作,所有的任务是串行执行的,如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它,此线程池保证所有任务的执行顺序按照任务的提交顺序执行。

3)newFixedThreadPool 创建固定大小的线程池,每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小,线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。

4)newScheduledThreadPool 创建一个大小无限的线程池,此线程池支持定时以及周期性执行任务的需求。

通过 ThreadPoolExecutor 的构造函数,看下线程池相关参数的概念:

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, 
        threadFactory, defaultHandler);
}

1)corePoolSize:线程池的核心线程数,一般情况下不管有没有任务都会一直在线程池中一直存活,只有在 ThreadPoolExecutor 中的方法 allowCoreThreadTimeOut(boolean value) 设置为 true 时,闲置的核心线程会存在超时机制,如果在指定时间没有新任务来时,核心线程也会被终止,而这个时间间隔由第 3 个属性 keepAliveTime 指定。

2)maximumPoolSize:线程池所能容纳的最大线程数,当活动的线程数达到这个值后,后续的新任务将会被阻塞。

3)keepAliveTime:控制线程闲置时的超时时长,超过则终止该线程。一般情况下用于非核心线程,只有在 ThreadPoolExecutor 中的方法 allowCoreThreadTimeOut(boolean value) 设置为 true 时,也作用于核心线程。

4)unit:用于指定 keepAliveTime 参数的时间单位,TimeUnit 是个 enum 枚举类型,常用的有:TimeUnit.HOURS(小时)、TimeUnit.MINUTES(分钟)、TimeUnit.SECONDS(秒) 和 TimeUnit.MILLISECONDS(毫秒) 等。

5)workQueue:线程池的任务队列,通过线程池的 execute(Runnable command) 方法会将任务 Runnable 存储在队列中。

6)threadFactory:线程工厂,它是一个接口,用来为线程池创建新线程的。

线程池的关闭

ThreadPoolExecutor 提供了两个方法,用于线程池的关闭,分别是 shutdown() 和 shutdownNow()。

shutdown():不会立即的终止线程池,而是要等所有任务缓存队列中的任务都执行完后才终止,但再也不会接受新的任务。
shutdownNow():立即终止线程池,并尝试打断正在执行的任务,并且清空任务缓存队列,返回尚未执行的任务。

扩展概念

  1. Callable 有返回值的线程或任务
  2. Future 主要用来获取 Callable 返回值
  3. FutureTask 实现了同时继承 Callable 和 Future 接口的 RunnableFuture 接口的实现类

通过例子学习上面三个概念

package com.carl.threaddemo;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class CallableThreadPoolDemo {

    public static ExecutorService single = Executors.newSingleThreadExecutor();

    public static void main(String[] args) throws InterruptedException {
        Callable<String> callable = new Callable<String>(){

            @Override
            public String call() throws Exception {
                Thread.sleep(1000);
                System.out.println("calling");
                return "haha";
            }

        };

        single.submit(callable);
//      Future<String> f = single.submit(callable);
//      try {
            //获取callable返回值
//          System.out.println(f.get());
//      } catch (ExecutionException e) {
//          e.printStackTrace();
//      }
        System.out.println("end");

    }

}

package com.carl.threaddemo;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class CallableFutureTask {

    public static void main(String[] args) throws InterruptedException, TimeoutException {
        Callable<String> callable = new Callable<String>(){

            @Override
            public String call() throws Exception {
                System.out.println(System.currentTimeMillis() + " calling");
                return "haha";
            }

        };


        FutureTask<String> fta = new FutureTask<String>(callable);
        new Thread(fta).start();
        System.out.println(System.currentTimeMillis() + " end");

        System.out.println();


        FutureTask<String> fts = new FutureTask<String>(callable);
        try {
            fts.run();
            fts.get();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println(System.currentTimeMillis() + " end");
    }

}

参考

《java 并发编程实战》


↙↙↙阅读原文可查看相关链接,并与作者交流