Java中线程的几种使用方式:
Runnable是一个接口,直接实现并在run方法中执行相应的任务。
private class MyRunnableTask implements Runnable { @Override public void run() { // running my task int index = 0; while (index < 10) { System.out.println("I'm the task " + (++index)); } } } public void createRunnable() { MyRunnableTask runnableTask = new MyRunnableTask(); runnableTask.run(); }普通线程创建和启动的方式,创建Thread的实例时将Runnable对象传入其中,start()启动线程即可:
public static void createThread() { Thread myThread = new Thread(new MyRunnableTask()); myThread.start(); }Executor是用于代替显示的Thread创建,ExecutorService是拥有服务生命周期的Executor(例如shutDown / terminal等),ExecutorService需要通过Executors使用工厂方法来进行创建:
public void createExecutor() { ExecutorService executorService = Executors.newCachedThreadPool(); executorService.execute(new MyRunnableTask()); }Executor的工厂方法工具集,提供了各类ThreadPool的创建方法。注意创建的都是ExecutorService类型的对象。如下所示创建一个含有固定线程数的线程池,nThreads代表线程数量。更多方法可以查阅Executors.java文件。
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }ExecutorService继承自Executor,提供了更多的生命周期相关的方法,例如:
void shutdown() <T> Future<T> submit(Callable<T> task) <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException省略…源码注释中提供了Usage Examples:
class NetworkService implements Runnable { private final ServerSocket serverSocket; private final ExecutorService pool; public NetworkService(int port, int poolSize) throws IOException { serverSocket = new ServerSocket(port); pool = Executors.newFixedThreadPool(poolSize); } public void run() { // run the service try { for (;;) { pool.execute(new Handler(serverSocket.accept())); } } catch (IOException ex) { pool.shutdown(); } } } class Handler implements Runnable { private final Socket socket; Handler(Socket socket) { this.socket = socket; } public void run() { // read and service request on socket } }以上代码可以看到,主要分为三个部分
构造函数的初始化,建立了一个Socket对象,同时创建了一个固定线程数的线程池实例。内部类Handler实现了Runnable方法,通过Socket进行相应的服务请求与读取run()方法中循环执行了Handler的任务这就是线程池相应的使用。简单来说其实线程池只是由于Thread的种种不便应运而生的一种线程处理机制,没有想象的那么复杂与麻烦。并且相对的比起Thread的普通创建方式来说,线程池能够节省资源开销,更合理和优雅的管理线程的状态。
Java通过Executor提供四种线程池:
CachedThreadPool : 将为每个任务都创建一个线程
FixedThreadPool : 预先执行代价高昂的线程分配,限制线程数量。优点是节省时间(创建线程需要开销)。直接从池中获取线程
SingleThreadExecutor : 以FIFO的入队方式处理任务。在第一个任务处理完之前第二个任务出于等待状态
ScheduledThreadPool : 能够延迟、周期性的执行任务,可以用于替换Timer我们同样使用线程池来进行之前的循环打印,注意使用Executors和ExecutorService需要将其进行包的导入,两者都属于java.util.concurrent路径下:
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class ThreadDemo { private static class MyRunnableTask implements Runnable { @Override public void run() { int index = 0; while (index < 10) { System.out.println("I'm the task " + (++index)); } } } public static void createRunnable() { MyRunnableTask runnableTask = new MyRunnableTask(); runnableTask.run(); } public static void createThread() { Thread myThread = new Thread(new MyRunnableTask()); myThread.start(); } public static void createThreadPool() { ExecutorService exec = Executors.newCachedThreadPool(); exec.execute(new MyRunnableTask()); } public static void main(String[] args) { // createThread(); // createRunnable(); createThreadPool(); } }三种方式都可以打印出相应的结果:
➜ ~ javac ThreadDemo.java ➜ ~ java ThreadDemo I'm the task 1 I'm the task 2 I'm the task 3 I'm the task 4 I'm the task 5 I'm the task 6 I'm the task 7 I'm the task 8 I'm the task 9 I'm the task 10