多线程及线程池
JAVA多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。
1、继承Thread类实现多线程
继承Thread类的方法尽管被我列为一种多线程实现方式,但Thread本质上也是实现了Runnable接口的一个实例,它代表一个线程的实例,并且,启动线程的唯一方法就是通过Thread类的start()实例方法。start()方法是一个native方法,它将启动一个新线程,并执行run()方法。这种方式实现多线程很简单,通过自己的类直接extend Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法。
package com.test; public class ThreadDemo { public static void main(String[] args) { MyThread myThread1 = new MyThread(); MyThread myThread2 = new MyThread(); myThread1.start(); myThread2.start(); } } class MyThread extends Thread { @Override public void run() { System.out.println(Thread.currentThread().getName()); } }
2、实现Runnable接口方式实现多线程
如果自己的类已经extends另一个类,就无法直接extends Thread,此时,必须实现一个Runnable接口。
package com.test; public class ThreadDemo { public static void main(String[] args) { MyThread myThread1 = new MyThread(); MyThread myThread2 = new MyThread(); Thread thread1 = new Thread(myThread1); Thread thread2 = new Thread(myThread2); thread1.start(); thread2.start(); } } class MyThread implements Runnable { @Override public void run() { System.out.println(Thread.currentThread().getName()); } }
3、使用ExecutorService、Callable、Future实现有返回结果的多线程
ExecutorService、Callable、Future这个对象实际上都是属于Executor框架中的功能类。执行Callable任务后,可以获取一个Future的对象,在该对象上调用get就可以获取到Callable任务返回的Object了,再结合线程池接口ExecutorService就可以实现传说中有返回结果的多线程了。
package com.test; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.concurrent.*; public class ThreadDemo { public static void main(String[] args) throws ExecutionException, InterruptedException { System.out.println("----程序开始运行----"); int taskSize = 5; // 创建一个线程池 ExecutorService pool = Executors.newFixedThreadPool(taskSize); // 创建多个有返回值的任务 List<Future> list = new ArrayList<>(); for (int i = 0; i < taskSize; ++i) { Callable c = new MyCallable(i + " "); // 执行任务并获取Future对象 Future f = pool.submit(c); list.add(f); } // 关闭线程池 pool.shutdown(); // 获取所有并发任务的运行结果 for (Future f : list) { // 从Future对象上获取任务的返回值 System.out.println(">>>" + f.get().toString()); } } } class MyCallable implements Callable<String> { private String taskNum; MyCallable(String taskNum) { this.taskNum = taskNum; } @Override public String call() throws InterruptedException { System.out.println(Thread.currentThread().getName()); System.out.println(">>>" + taskNum + "任务启动"); Date dateTmp1 = new Date(); Thread.sleep(1000); Date dateTmp2 = new Date(); long time = dateTmp2.getTime() - dateTmp1.getTime(); System.out.println(">>>" + taskNum + "任务终止"); return taskNum + "任务返回运行结果,当前任务时间【" + time + "毫秒】"; } }
线程池的作用:
1、降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
2、提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
3、提高线程的可管理性。
线程池:提供了一个线程队列,队列中保存着所有等待状态的线程。避免了创建与销毁额外开销,提高了响应的速度。
线程池的体系结构:
java.util.concurrent.Executor : 负责线程的使用与调度的根接口
|--ExecutorService 子接口: 线程池的主要接口
|--ThreadPoolExecutor 线程池的实现类
|--ScheduledExecutorService 子接口:负责线程的调度
|--ScheduledThreadPoolExecutor :继承 ThreadPoolExecutor, 实现 ScheduledExecutorService
工具类 : Executors
ExecutorService newFixedThreadPool() : 创建固定大小的线程池
ExecutorService newCachedThreadPool() : 缓存线程池,线程池的数量不固定,可以根据需求自动的更改数量。
ExecutorService newSingleThreadExecutor() : 创建单个线程池。线程池中只有一个线程
ScheduledExecutorService newScheduledThreadPool() : 创建固定大小的线程,可以延迟或定时的执行任务。
参考:http://www.cnblogs.com/dolphin0520/p/3932921.html