Java并发编程——Executor框架

今天看到《Java并发编程实战》第六章的时候,书中讲了利用Executor框架来实现多线程,平时Executor用得不多,今天顺带学习了一下,写出来总结总结。

引入Executor框架的原因

两种多线程执行任务的策略:

1.串行执行,即每次线程运行完才会运行下一个线程。这种方法是线程安全的,但是效率低,吞吐量小

2.为每个任务开辟一个线程,例如为每个请求服务器的连接建立一个线程,这种方法开销大(频繁地创建和销毁线程消耗大量资源,线程之间互相争夺处理资源等)以及有稳定性因素(线程的数量限制)

为了可以实现线程重用,对线程进行统一的管理,控制线程的数量,采用了线程池的方法。

使用方法

一、Executor框架使用Runnable作为其基本任务的表现形式

先看几个用到的接口(Executor,ExecutorService)

Executor接口

public interface Executor {
    void execute(Runnable command);
}

只要传入Runnable接口,调用execute方法即可开启线程。

ExecutorService接口(继承自Executor)

public interface ExecutorService extends Executor {

    void shutdown();
    List shutdownNow();
    boolean isShutdown();
    boolean isTerminated();
    boolean awaitTermination(long timeout, TimeUnit unit)
        throws InterruptedException;
     Future submit(Callable task);
     Future submit(Runnable task, T result);
    Future submit(Runnable task);
     List> invokeAll(Collection> tasks)
        throws InterruptedException;
     List> invokeAll(Collection> tasks,
                                  long timeout, TimeUnit unit)
        throws InterruptedException;
     T invokeAny(Collection> tasks)
        throws InterruptedException, ExecutionException;
     T invokeAny(Collection> tasks,
                    long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

submit方法,可以传入Runnable接口和Callable接口,然后返回Future接口

1、利用工厂方法创建线程池

利用Executors类的工厂方法来创建线程池,以下是Executors类提供的常用的工厂方法

1.public static ExecutorService newFixedThreadPool(int nThreads)
创建固定数目线程的线程池。每当提交一个任务就创建一个线程,直到达到线程池的最大数量。

2.public static ExecutorService newCachedThreadPool()
创建一个可缓存的线程池,如果线程池的规模超过了处理需求时,就会回收空闲的线程,而当需求增加时,则可以添加新的线程,线程池的规模不存在限制。

3.public static ExecutorService newSingleThreadExecutor()
创建一个单线程化的Executor。可以确保任务在队列中串行执行(例如FIFO,LIFO,优先级)

4.public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
创建一个可以以延时或定时的方式执行任务的线程池,类似Timer。

2、实现Runnable接口

3、调用Executor的execute()方法

例子:

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class ExecutorDemo{

	public static void main(String[] args) {
		//创建有5个线程的线程池
		Executor executor = Executors.newFixedThreadPool(5);	
		for (int i = 0; i < 10; i++){
			ExecutorTest e = new ExecutorTest(String.valueOf(i));
			executor.execute(e);
		}
		//这里不知道如何结束,看完第七章再来补充
	}
}

class ExecutorTest implements Runnable{
	String name;
	ExecutorTest(String name){
		this.name = name;
	}

	@Override
	public void run(){
		System.out.println("I am Thread " + name);
	}
}

二、通过Future和Callable创建带返回值的线程

为什么需要用Callalbe呢,因为Runnable不能返回结果或者抛出异常

先看几个接口(Runnable,Callable,RunnableFuture,Future)

Runnable接口

public interface Runnable {
    public abstract void run();
}

run()方法中完成任务

Callable接口

public interface Callable {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

 call()方法有返回结果,并且可以抛出Exception

RunnableFuture接口

public interface RunnableFuture extends Runnable, Future {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}

Future接口 ,Future表示一个任务的生命周期,并提供了相应的方法来判断是否完成,是否取消,获取任务的结果,取消任务

public interface Future {
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    boolean isDone();
    V get() throws InterruptedException, ExecutionException;
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

get()方法可以返回结果,不过需要等待任务完成才有返回值

再看一个类(FutureTask,java.util.concurrent包中唯一实现了Future接口的类)

public class FutureTask implements RunnableFuture {
    public FutureTask(Callable callable) {...}
    public FutureTask(Runnable runnable, V result){...}
}

使用方法一

1、实例化一个FutureTask类,传入Callable接口或实现了Callable接口的实例

2、启动线程

   将FutureTask传入Thread的构造函数中,调用Thread的start()方法启动线程

import java.util.concurrent.FutureTask;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class FutureTaskDemo{

	public static void main(String[] args) throws Exception{
		for (int i = 0; i < 10; i++){
			CallableTest c = new CallableTest(String.valueOf(i));
			FutureTask future = new FutureTask(c);
			new Thread(future).start();
			String result = future.get(); //这里阻塞等待了
			System.out.println(result);
		}
	}	
}

//不需要返回结果时可以写Void
class CallableTest implements Callable{
	String name;

	CallableTest(String name){
		this.name = name;
	}

	public String call() throws Exception{
		return "I am Thread " + name;
	}
}

使用方法二(利用Executor框架,Executor的execute方法执行任务)

1、实例化一个FutureTask类,传入Callable接口或实现了Callable接口的实例

2、调用Executor框架的execute()方法

import java.util.concurrent.FutureTask;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

public class FutureTaskDemo{

	public static void main(String[] args) throws Exception{
		Executor exec = Executors.newFixedThreadPool(1);
		CallableTest c = new CallableTest("master");
		FutureTask future = new FutureTask(c);
		exec.execute(future);
		System.out.println(future.get());
	}	
}

//不需要返回结果时可以写Void
class CallableTest implements Callable{
	String name;

	CallableTest(String name){
		this.name = name;
	}

	public String call() throws Exception{
		return "I am Thread " + name;
	}
}

使用方法三,利用ExecutorService的submit()

调用ExecutorService的submit()获得Future接口

import java.util.concurrent.FutureTask;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

public class FutureTaskDemo{

	public static void main(String[] args) throws Exception{
		CallableTest c = new CallableTest("master");
		ExecutorService exec = Executors.newFixedThreadPool(1);
		Future future = exec.submit(c);
		System.out.println(future.get());
	}	
}

//不需要返回结果时可以写Void
class CallableTest implements Callable{
	String name;

	CallableTest(String name){
		this.name = name;
	}

	public String call() throws Exception{
		return "I am Thread " + name;
	}
}

 

——————————

2019.5.4 回头补上取消和终止Executor的部分

 

 

你可能感兴趣的:(Java并发编程实战)