ExecutorService实现java多线程



在Java5之后,并发线程这块发生了根本的变化,最重要的莫过于新的启动、调度、管理线程的一大堆API了。在Java5以后,通过Executor来启动线程比用Thread的start()更好。在新特征中,可以很容易控制线程的启动、执行和关闭过程,还可以很容易使用线程池的特性。
 

一、创建任务

 
任务就是一个实现了Runnable接口 或者Thread的接口的类。
创建的时候实run方法即可。
 

二、执行任务

 
通过java.util.concurrent.ExecutorService接口对象来执行任务,该接口对象通过工具类java.util.concurrent.Executors的静态方法来创建。
 
Executors此包中所定义的 Executor、ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 类的工厂和实用方法。
 
ExecutorService提供了管理终止的方法,以及可为跟踪一个或多个异步任务执行状况而生成 Future 的方法。 可以关闭 ExecutorService,这将导致其停止接受新任务。关闭后,执行程序将最后终止,这时没有任务在执行,也没有任务在等待执行,并且无法提交新任务。
            executorService.execute(new TestRunnable());
 
1、创建ExecutorService
通过工具类java.util.concurrent.Executors的静态方法来创建。
Executors此包中所定义的 Executor、ExecutorService、ScheduledExecutorService、ThreadFactory 和 Callable 类的工厂和实用方法。
 
比如,创建一个ExecutorService的实例,ExecutorService实际上是一个线程池的管理工具:
        ExecutorService executorService = Executors.newCachedThreadPool();
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        ExecutorService executorService = Executors.newSingleThreadExecutor();
 
2、将任务添加到线程去执行
当将一个任务添加到线程池中的时候,线程池会为每个任务创建一个线程,该线程会在之后的某个时刻自动执行。
 

三、关闭执行服务对象

        executorService.shutdown();
 

四、综合实例

用法一:

AutoLoad.class
package test.autorun;


import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;





public class AutoLoad  {
public static void main(String[] args) {

		//多线程
		ExecutorService executorService = Executors.newFixedThreadPool(30);
		for (int i = 0; i < 30; i++) {
		IpFilter thread = new IpFilter();
		executorService.submit(thread);
		}
		executorService.shutdown();
//		IpFilter filter = new IpFilter();
//		filter.start();
	}
	
}

IpFilter .class

package test.autorun;           
   public class IpFilter extends Thread {	public void run() {  
		System.out.println("已经自动运行");
		}
}


用法二

package concurrent; 

import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 

/** 
* Created by IntelliJ IDEA. 
* 
* @author leizhimin 2008-11-25 14:28:59 
*/ 
public class TestCachedThreadPool { 
        public static void main(String[] args) { 
//                ExecutorService executorService = Executors.newCachedThreadPool(); 
                ExecutorService executorService = Executors.newFixedThreadPool(5);
//         ExecutorService executorService = Executors.newSingleThreadExecutor();

                for (int i = 0; i < 5; i++) { 
                        executorService.execute(new TestRunnable()); 
                        System.out.println("************* a" + i + " *************"); 
                } 
                executorService.shutdown(); 
        } 
} 

class TestRunnable implements Runnable { 
        public void run() { 
                System.out.println(Thread.currentThread().getName() + "线程被调用了。"); 
                while (true) { 
                        try { 
                                Thread.sleep(5000); 
                                System.out.println(Thread.currentThread().getName()); 
                        } catch (InterruptedException e) { 
                                e.printStackTrace(); 
                        } 
                } 
        } 
}


五、exceute和submit的区别

三个区别:

1、接收的参数不一样

2、submit有返回值,而execute没有

Method submit extends base method Executor.execute by creating and returning a Future that can be used to cancel execution and/or wait for completion. 

用到返回值的例子,比如说我有很多个做validation的task,我希望所有的task执行完,然后每个task告诉我它的执行结果,是成功还是失败,如果是失败,原因是什么。然后我就可以把所有失败的原因综合起来发给调用者。

个人觉得cancel execution这个用处不大,很少有需要去取消执行的。

而最大的用处应该是第二点。

3、submit方便Exception处理

There is a difference when looking at exception handling. If your tasks throws an exception and if it was submitted with execute this exception will go to the uncaught exception handler (when you don't have provided one explicitly, the default one will just print the stack trace to System.err). If you submitted the task with submit any thrown exception, checked or not, is then part of the task's return status. For a task that was submitted with submit and that terminates with an exception, the Future.get will rethrow this exception, wrapped in an ExecutionException.

意思就是如果你在你的task里会抛出checked或者unchecked exception,而你又希望外面的调用者能够感知这些exception并做出及时的处理,那么就需要用到submit,通过捕获Future.get抛出的异常。


比如说,我有很多更新各种数据的task,我希望如果其中一个task失败,其它的task就不需要执行了。那我就需要catch Future.get抛出的异常,然后终止其它task的执行,代码如下:

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
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 ExecutorServiceTest {
	public static void main(String[] args) {
		ExecutorService executorService = Executors.newCachedThreadPool();
		List<Future<String>> resultList = new ArrayList<Future<String>>();

		// 创建10个任务并执行
		for (int i = 0; i < 10; i++) {
			// 使用ExecutorService执行Callable类型的任务,并将结果保存在future变量中
			Future<String> future = executorService.submit(new TaskWithResult(i));
			// 将任务执行结果存储到List中
			resultList.add(future);
		}
		executorService.shutdown();

		// 遍历任务的结果
		for (Future<String> fs : resultList) {
			try {
				System.out.println(fs.get()); // 打印各个线程(任务)执行的结果
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (ExecutionException e) {
				executorService.shutdownNow();
				e.printStackTrace();
				return;
			}
		}
	}
}

class TaskWithResult implements Callable<String> {
	private int id;

	public TaskWithResult(int id) {
		this.id = id;
	}

	/**
	 * 任务的具体过程,一旦任务传给ExecutorService的submit方法,则该方法自动在一个线程上执行。
	 * 
	 * @return
	 * @throws Exception
	 */
	public String call() throws Exception {
		System.out.println("call()方法被自动调用,干活!!!             " + Thread.currentThread().getName());
		if (new Random().nextBoolean())
			throw new TaskException("Meet error in task." + Thread.currentThread().getName());
		// 一个模拟耗时的操作
		for (int i = 999999999; i > 0; i--)
			;
		return "call()方法被自动调用,任务的结果是:" + id + "    " + Thread.currentThread().getName();
	}
}

class TaskException extends Exception {
	public TaskException(String message) {
		super(message);
	}
}
可以看见一旦某个task出错,其它的task就停止执行。



参考链接:

http://lavasoft.blog.51cto.com/62575/115112

http://blog.csdn.net/peachpi/article/details/6771946

你可能感兴趣的:(thread,多线程,线程池,executorService,submit)