文章目录
线程是由操作系统来进行调度的
1、实现多线程的四种方式
-
继承Thread类
Tread类本质上就是一个实现了Runnable接口的一个实例,代表一个线程的实例。启动线程的唯一方法是通过Thread的类的start()实例方法。start()是一个本地方法,它将启动一个新线程,并执行run()方法。
通过自己的类直接继承Tread类,并重写run()方法。
-
实现Runnable接口
因为继承是单继承,所以当自己的类已经继承了另一个类的时候,就无法使用extends Tread了,可以实现Runnable接口,并实现run()方法。使用时先实例化一个Tread,并传入自己的对象实例,当执行Tread.start()的时候,Tread的run()方法就会调用目标对象的run()方法
public void run() { if (target != null) { target.run(); } }
-
实现callable接口,通过futureTask包装器来创建Tread线程
public interface Callable<V> { V call() throws Exception; } public class SomeCallable<V> extends OtherClass implements Callable<V> { @Override public V call() throws Exception { return null; } } //第一种,使用Tread Callable<V> oneCallable = new SomeCallable<V>(); FutureTask<V> oneTask = new FutureTask<V>(oneCallable); Thread oneThread = new Thread(oneTask); oneThread.start(); //第二种,使用线程池 ExecutorService executor = Executors.newCachedThreadPool(); Callable<V> oneCallable = new SomeCallable<V>(); FutureTask<Integer> futureTask = new FutureTask<Integer>(oneCallable); executor.submit(futureTask); executor.shutdown();
-
使用ExecutorService、Callable、Future实现有返回结果的线程
public interface Future<V> { boolean cancel(boolean mayInterruptIfRunning); boolean isCancelled();//表示任务是否被取消成功,如果任务正常完成前被取消成功,则返回true boolean isDone();//表示任务是否已经完成,若任务完成,返回true V get() throws InterruptedException, ExecutionException;//会产生阻塞,直到任务执行完毕 V get(long timeout, TimeUnit unit)//指定时间内没获取到结果,直接返回null throws InterruptedException, ExecutionException, TimeoutException; } // 创建一个线程池 ExecutorService pool = Executors.newFixedThreadPool(5); // 创建多个有返回值的任务 List<Future> list = new ArrayList<Future>(); for (int i = 0; i < 5; i++) { Callable c = new MyCallable(i + " "); // 执行任务并获取Future对象 Future f = pool.submit(c); // System.out.println(">>>" + f.get().toString()); list.add(f); } // 关闭线程池 pool.shutdown(); // 获取所有并发任务的运行结果 for (Future f : list) { // 从Future对象上获取任务的返回值,并输出到控制台 System.out.println(">>>" + f.get().toString()); }
2、线程池
- java.uitl.concurrent.ThreadPoolExecutor类是线程池最核心的类
//构造函数
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,
long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,RejectedExecutionHandler handler);
-
corePoolSize:核心池大小,当线程池中的线程数目达到corePoolSize大小后,就会把任务放到缓存队列
-
maximumPoolSize:线程池的最大线程数,表示线程池最多能创建多少线程
当一个新的任务被提交到线程池的时候,1>,先判断核心池是否已满,未满则创建一个新的线程来执行该任务;满了则去判断任务队列是否已满,未满则将新提交的任务存储在工作队列中;满了则去判断最大线程数是否已满,未满则创建一个新的工作线程去执行任务;满了则交给饱和策略来处理这个任务。如果线程池中的线程数大于核心池大小,则当某个线程空闲时间超过keepAliveTime时,该线程会被终止
-
keepAliveTime:默认情况下,只有当线程池中的线程数量大于核心池时,这个参数才会起作用
-
unit :是keepAliveTime的时间单位
-
workQueue:是一个阻塞队列,用来存储等待执行的任务
-
threadFactory:线程工厂,主要用来创建线程
-
handler:表示当拒绝任务处理时的策略
- AbortPolicy:丢弃任务并抛出RejectedExecutionException异常
- DiscardPolicy:丢弃任务,但不抛出异常
- DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
- CallerRunsPolicy:由调用线程处理该任务
-
ThreadPoolExecutor有几个重要的方法:
- execute():向线程池提交一个任务,交由线程池去执行
- submit():也是向线程池提交任务,和execute()的区别是submit()能够返回任务的执行结果,实际上调用的还是execute(),只不过利用Future()来获取任务的执行结果
- shutdown():关闭线程池,此时线程池不能够接受新的任务,他会等待所有任务执行完毕
- shutdownNow():关闭线程池,此时线程池不能接受新的任务,并且尝试终止正在进行的任务
-
线程池的状态:
volatile int runState; static final int RUNNING = 0; static final int SHUTDOWN = 1; static final int STOP = 2; static final int TERMINATED = 3;
runState:表示当前线程池的状态,使用volatile修饰来保证线程之前的可见性
-
线程池中的线程初始化
默认情况下,创建线程池之后,线程池中是没有线程的,需要提交任务之后才会创建线程
在实际中如果需要线程池创建之后 立即创建线程,可以通过两个方法来实现:
- prestartCoreThread():初始化一个核心线程
- prestartAllCoreThreads():初始化核心池数量的线程
-
任务缓存队列及排队策略
workQueue的类型为BlockingQueue,通常有三种类型:
- ArrayBlockingQueue:基于数组的先进先出队列,此队列创建时必须指定大小
- LinkedBlockingQueue:基于链表的阻塞队列,如果创建时没有指定此队列的大小,默认为Integer.MAX_VALUE;
- SynchronousQueue:这个队列比较特殊,不会保存提交的任务,而是直接新建一个线程来执行新来的任务
-
具体使用
Executors.newCachedThreadPool(); //创建一个缓冲池,缓冲池容量大小为Integer.MAX_VALUE Executors.newSingleThreadExecutor(); //创建容量为1的缓冲池 Executors.newFixedThreadPool(int); //创建固定容量大小的缓冲池
具体实现:
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); } public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); } public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
从它们的具体实现来看,它们实际上也是调用了ThreadPoolExecutor,只不过参数都已配置好了。