Skip to main content
 首页 » 编程设计

java线程池框架

2022年07月19日163jyk

java线程池框架

 

java.util.concurrent.ExecutorService接口表现异步执行机制,使任务在后台执行。ExecutorService在包java.util.concurrent中作为线程池实现类。

ExecutorService 示例

简单的Java ExectorService 示例:

ExecutorService executorService = Executors.newFixedThreadPool(10); 
 
executorService.execute(new Runnable() { 
    public void run() { 
        System.out.println("Asynchronous task"); 
    } 
}); 
 
executorService.shutdown();


使用工厂方法创建ExecutorService线程池对象,包含10个线程。然后一个Runnable接口的匿名实现,传给execute方法。ExecutorService线程池中的一个线程负责执行。

委托任务异步执行

图示一个线程委托一个任务给ExecutorService线程池异步执行,主线程继续执行,和被委托的任务执行线程完全独立。



ExecutorService实现类

ExecutorService是接口,实际使用需要有对应实现类。在java.util.concurrent包有下面的实现类。

Creating anExecutorService

如何通过ExecutorService实现类创建ExecutorService,一般可以通过Executors的工厂方法创建ExecutorService实现类,下面三个示例代码:

ExecutorService executorService1 = Executors.newSingleThreadExecutor(); 
 
ExecutorService executorService2 = Executors.newFixedThreadPool(10); 
 
ExecutorService executorService3 = Executors.newScheduledThreadPool(10);


ExecutorService 常用方法

有几种方式可以委托任务给ExecutorService去执行。

  • execute(Runnable)
  • submit(Runnable)
  • submit(Callable)
  • invokeAny(...)
  • invokeAll(...)

下面依次说明每个方法。

execute(Runnable)

execute(Runnable) 方法需要一个java.lang.Runnable接口实现对象,异步执行。示例如下:

<pre name="code" class="java">ExecutorService executorService = Executors.newSingleThreadExecutor(); 
 
executorService.execute(new Runnable() { 
    public void run() { 
        System.out.println("Asynchronous task"); 
    } 
}); 
 
executorService.shutdown();

 


上面代码无法获得执行的Runnable的结果,可以通过Callable实现,请继续往下阅读。

submit(Runnable)

The submit(Runnable) 方法也需要一个Runnable 接口实现对象, 但可以返回一个Future对象。Future 对象可以用来检查Runnable任务是否执行完成。示例代码如下:

Future future = executorService.submit(new Runnable() { 
 
    public void run() { 
 
        System.out.println("Asynchronous task"); 
 
    } 
 
}); 
 
future.get();  //如果任务正确执行完毕,返回null值。

submit(Callable)

The submit(Callable)方法与submit(Runnable)方法类似,但参数类型不同。Callable 实例与Runnable差不多,除了Callable.call() 方法能返回一个结果,Runnable.run()方法不能有返回值。Callable的结果可以通过Future对象获得,示例代码如下:

Future future = executorService.submit(new Callable(){ 
 
    public Object call() throws Exception { 
 
        System.out.println("Asynchronous Callable"); 
 
        return "Callable Result"; 
 
    } 
 
}); 
 
System.out.println("future.get() = " + future.get()); 
 
上面的代码输出如下: 
 
Asynchronous Callable 
 
future.get() = Callable Result

invokeAny()

invokeAny()方法需要Callable 集合对象,或Callable的子接口对象集合。执行该方法不返回Future对象,但返回其中一个Calllable对象的执行结果,但无法确认是具体那个Callable的对象,仅是所有执行完成对象的其中一个。如果其中一个任务完成(或在抛出异常),剩下的Calllable任务将取消继续执行。示例代码如下:

ExecutorService executorService = Executors.newSingleThreadExecutor(); 
 
Set<Callable<String>> callables = new HashSet<Callable<String>>(); 
 
callables.add(new Callable<String>() { 
    public String call() throws Exception { 
        return "Task 1"; 
    } 
 
}); 
 
callables.add(new Callable<String>() { 
    public String call() throws Exception { 
        return "Task 2"; 
    } 
}); 
 
callables.add(new Callable<String>() { 
    public String call() throws Exception { 
        return "Task 3"; 
    } 
}); 
 
String result = executorService.invokeAny(callables); 
System.out.println("result = " + result); 
executorService.shutdown();

上述代码将打印集合中一个Calllable任务返回值,我测试了几次,结果都不同,有时是"Task 1",有时是"Task 2",情况不确定。

invokeAll()

 invokeAll() 方法执行传递的参数集合中所有的Callable对象。invokeAll() 返回一个Future对象list,通过list你能获得每个Callable对象的执行结果。记住,有的任务可能完成因为异常,所以不能成功,但Future对象无法区分。示例代码如下:

ExecutorService executorService = Executors.newSingleThreadExecutor(); 
 
Set<Callable<String>> callables = new HashSet<Callable<String>>(); 
 
callables.add(new Callable<String>() { 
    public String call() throws Exception { 
        return "Task 1"; 
    } 
}); 
 
callables.add(new Callable<String>() { 
    public String call() throws Exception { 
        return "Task 2"; 
    } 
}); 
 
callables.add(new Callable<String>() { 
    public String call() throws Exception { 
        return "Task 3"; 
    } 
}); 
 
List<Future<String>> futures = executorService.invokeAll(callables); 
 
for(Future<String> future : futures){ 
    System.out.println("future.get = " + future.get()); 
} 
 
executorService.shutdown();


ExecutorService的Shutdown方法

当使用ExecutorService时,最后应该调用shutdown方法,这样所有的线程将不再运行。

例如,如果你的应用通过main方法启动,则主线程负责结束应用程序。如果你应用中ExexutorService 是活动的,则应用继续保持运行状态。活动的ExexutorService 阻止JVM停止应用。

为了终止ExecutorService里的线程任务,你可以调用shutdown()方法。但ExecutorService并不立刻停止,但不在接受新的任务,一旦所有的线程都完成了当前任务,ExecutorService停止。所有提交到ExecutorService的任务在调用shutdown()方法之前被执行。

如果你想立刻结束ExecutorService,你可以调用shutdownNow()方法。 它将立刻停止所有执行任务,并跳过所有提交了但未处理的任务。正在执行的任务无法确定如果结束,可能立刻停止,可能直到执行完成停止。


本文参考链接:https://blog.csdn.net/neweastsun/article/details/52565891
阅读延展