- 引入Executor
- 建立Executor
- 建立固定大小的執行緒Executor
引入Executor
我們在開發Java多執行緒程式的時候,往往會建立很多個Runnable物件,然後建立對應的Thread物件來執行它們。但是,如果需要開發一個大量的併發任務,過多的任務就會導致下面這些問題:
- 必須給每個Runnable物件建立一個Thread,也就意味著要建立相關的執行緒建立,結束,取結果的程式碼,程式碼很冗餘
- 過多的Thread物件對於降低了應用程式的效率,系統負荷過重
從Java 5之後,引入了一套API框架用來解決這個問題。這套新的框架就是執行器框架(Executor Framework),圍繞著Executor介面和它的自介面的ExecutorService,以及實現這兩個介面的ThreadPoolExecutor類。
部分繼承關係:
這套框架分離了任務的建立和執行。使用Executor,只要將Runnable物件,直接丟給執行器就可以了。Executor會自己建立執行緒,來負責這些Runnable物件任務的執行。Executor有一個好處就是利用執行緒池提高效能,當收到一個新任務時,會嘗試使用執行緒池中的空閒執行緒來執行,避免了重複建立過多的執行緒而導致系統效能的下降。
建立Executor
使用Executor的第一步就是建立一個執行緒池物件,java提供了Executors的工廠類,可以幫我們建立不同的執行緒池物件
然後呼叫Executor的execute方法執行相應的執行緒,並且要顯示的結束執行緒池 server類:
package CreateExecutor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
public class Server {
private ThreadPoolExecutor executor;
public Server() {
executor = (ThreadPoolExecutor)Executors.newCachedThreadPool();
}
public void executorTask(Task task) {
System.out.println("a new task arrived");
executor.execute(task);
System.out.println("Server : Pool Size :" + executor.getPoolSize());
System.out.println("Server : ActiveCount :" + executor.getActiveCount());
System.out.println("Server : CompletedTaskCount :" + executor.getCompletedTaskCount());
System.out.println();
}
public void endServer() {
executor.shutdown();
}
}
複製程式碼
Task類用來建立多個runnable物件
package CreateExecutor;
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class Task implements Runnable {
private Date initDate;
private String name;
public Task(Date initDate, String name) {
super();
this.initDate = initDate;
this.name = name;
}
@Override
public void run() {
System.out.printf("%s : Task %s : Created on : %s\n",
Thread.currentThread().getName(),name,initDate);
System.out.printf("%s : Task %s : Started on : %s\n",
Thread.currentThread().getName(),name, new Date());
//將任務休眠一段時間,模擬任務的執行
try {
Long duration = (long)(Math.random() * 10);
System.out.printf("%s : Task %s : Doing a task during %d seconds\n",
Thread.currentThread().getName(), name, duration);
TimeUnit.SECONDS.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("%s : Task %s : Finished on : %s\n",
Thread.currentThread().getName(), name, new Date());
}
}
複製程式碼
Main類測試:
package CreateExecutor;
import java.util.Date;
public class Main {
public static void main(String[] args) {
Server server = new Server();
for(int i=0;i<10;i++) {
Task task = new Task(new Date(), "Task " + i);
server.executorTask(task);
}
server.endServer();
}
}
複製程式碼
執行結果
a new task arrived
Server : Pool Size :1
pool-1-thread-1 : Task Task 0 : Created on : Mon Jul 24 20:31:10 CST 2017
pool-1-thread-1 : Task Task 0 : Started on : Mon Jul 24 20:31:11 CST 2017
Server : ActiveCount :1
Server : CompletedTaskCount :0
a new task arrived
Server : Pool Size :2
Server : ActiveCount :2
Server : CompletedTaskCount :0
a new task arrived
Server : Pool Size :3
Server : ActiveCount :3
Server : CompletedTaskCount :0
a new task arrived
Server : Pool Size :4
Server : ActiveCount :4
Server : CompletedTaskCount :0
a new task arrived
Server : Pool Size :5
Server : ActiveCount :5
Server : CompletedTaskCount :0
pool-1-thread-2 : Task Task 1 : Created on : Mon Jul 24 20:31:11 CST 2017
pool-1-thread-2 : Task Task 1 : Started on : Mon Jul 24 20:31:11 CST 2017
pool-1-thread-5 : Task Task 4 : Created on : Mon Jul 24 20:31:11 CST 2017
pool-1-thread-4 : Task Task 3 : Created on : Mon Jul 24 20:31:11 CST 2017
pool-1-thread-3 : Task Task 2 : Created on : Mon Jul 24 20:31:11 CST 2017
pool-1-thread-1 : Task Task 0 : Doing a task during 3 seconds
pool-1-thread-3 : Task Task 2 : Started on : Mon Jul 24 20:31:11 CST 2017
pool-1-thread-3 : Task Task 2 : Doing a task during 8 seconds
pool-1-thread-4 : Task Task 3 : Started on : Mon Jul 24 20:31:11 CST 2017
pool-1-thread-4 : Task Task 3 : Doing a task during 7 seconds
pool-1-thread-5 : Task Task 4 : Started on : Mon Jul 24 20:31:11 CST 2017
pool-1-thread-2 : Task Task 1 : Doing a task during 9 seconds
pool-1-thread-5 : Task Task 4 : Doing a task during 1 seconds
pool-1-thread-5 : Task Task 4 : Finished on : Mon Jul 24 20:31:12 CST 2017
pool-1-thread-1 : Task Task 0 : Finished on : Mon Jul 24 20:31:14 CST 2017
pool-1-thread-4 : Task Task 3 : Finished on : Mon Jul 24 20:31:18 CST 2017
pool-1-thread-3 : Task Task 2 : Finished on : Mon Jul 24 20:31:19 CST 2017
pool-1-thread-2 : Task Task 1 : Finished on : Mon Jul 24 20:31:20 CST 2017
複製程式碼
Executor的一個特性,必須通過顯示的結束,如果不這麼做,Executor會繼續執行,執行緒也不會結束,程式也不會結束。如果Executor沒有任務可執行了,它不會結束,會一直等待新的任務到來,而不會結束執行。
建立固定大小的執行緒Executor
上面的例子,對五個任務新生成了5個執行緒,為了重複利用執行緒,我們可以建立固定的執行緒數,Executors工廠類就提供了這麼一個工廠方法。 這個Executor會有一個最大的執行緒最大數,如果傳送超過這個任務數的任務給Executor,執行器不會再建立額外的執行緒,剩下的任務將被阻塞直到Executor有足夠的空閒的執行緒可用。
package CreateFixedExecutor;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
public class Server {
private ThreadPoolExecutor executor;
public Server() {
executor = (ThreadPoolExecutor)Executors.newFixedThreadPool(5);
}
public void executorTask(Task task) {
System.out.println("a new task arrived\n");
executor.execute(task);
System.out.println("Server : Pool Size :" + executor.getPoolSize());
System.out.println("Server : ActiveCount :" + executor.getActiveCount());
System.out.println("Server : TaskCount :" + executor.getTaskCount());
System.out.println("Server : CompletedTaskCount :" + executor.getCompletedTaskCount());
}
public void endServer() {
executor.shutdown();
}
}
複製程式碼
package CreateFixedExecutor;
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class Task implements Runnable {
private Date initDate;
private String name;
public Task(Date initDate, String name) {
super();
this.initDate = initDate;
this.name = name;
}
@Override
public void run() {
System.out.printf("%s : Task %s : Created on : %s\n",
Thread.currentThread().getName(),name,initDate);
System.out.printf("%s : Task %s : Started on : %s\n",
Thread.currentThread().getName(),name, new Date());
//將任務休眠一段時間,模擬任務的執行
try {
Long duration = (long)(Math.random() * 10);
System.out.printf("%s : Task %s : Doing a task during %d seconds\n",
Thread.currentThread().getName(), name, duration);
TimeUnit.SECONDS.sleep(duration);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("%s : Task %s : Finished on : %s\n",
Thread.currentThread().getName(), name, new Date());
}
}
複製程式碼
package CreateFixedExecutor;
import java.util.Date;
public class Main {
public static void main(String[] args) {
Server server = new Server();
for(int i=0;i<10;i++) {
Task task = new Task(new Date(), "Task " + i);
server.executorTask(task);
}
server.endServer();
}
}
複製程式碼
執行結果:
a new task arrived
Server : Pool Size :1
pool-1-thread-1 : Task Task 0 : Created on : Mon Jul 24 20:40:07 CST 2017
Server : ActiveCount :1
Server : TaskCount :1
Server : CompletedTaskCount :0
a new task arrived
pool-1-thread-1 : Task Task 0 : Started on : Mon Jul 24 20:40:07 CST 2017
Server : Pool Size :2
Server : ActiveCount :2
Server : TaskCount :2
Server : CompletedTaskCount :0
a new task arrived
Server : Pool Size :3
Server : ActiveCount :3
Server : TaskCount :3
Server : CompletedTaskCount :0
a new task arrived
Server : Pool Size :4
Server : ActiveCount :4
Server : TaskCount :4
Server : CompletedTaskCount :0
a new task arrived
Server : Pool Size :5
Server : ActiveCount :5
Server : TaskCount :5
Server : CompletedTaskCount :0
a new task arrived
Server : Pool Size :5
Server : ActiveCount :5
Server : TaskCount :6
Server : CompletedTaskCount :0
a new task arrived
Server : Pool Size :5
pool-1-thread-2 : Task Task 1 : Created on : Mon Jul 24 20:40:07 CST 2017
pool-1-thread-2 : Task Task 1 : Started on : Mon Jul 24 20:40:07 CST 2017
Server : ActiveCount :5
pool-1-thread-2 : Task Task 1 : Doing a task during 7 seconds
pool-1-thread-4 : Task Task 3 : Created on : Mon Jul 24 20:40:07 CST 2017
pool-1-thread-4 : Task Task 3 : Started on : Mon Jul 24 20:40:07 CST 2017
pool-1-thread-1 : Task Task 0 : Doing a task during 9 seconds
pool-1-thread-3 : Task Task 2 : Created on : Mon Jul 24 20:40:07 CST 2017
pool-1-thread-3 : Task Task 2 : Started on : Mon Jul 24 20:40:07 CST 2017
pool-1-thread-4 : Task Task 3 : Doing a task during 2 seconds
pool-1-thread-5 : Task Task 4 : Created on : Mon Jul 24 20:40:07 CST 2017
pool-1-thread-5 : Task Task 4 : Started on : Mon Jul 24 20:40:07 CST 2017
pool-1-thread-5 : Task Task 4 : Doing a task during 5 seconds
Server : TaskCount :7
pool-1-thread-3 : Task Task 2 : Doing a task during 4 seconds
Server : CompletedTaskCount :0
a new task arrived
Server : Pool Size :5
Server : ActiveCount :5
Server : TaskCount :8
Server : CompletedTaskCount :0
a new task arrived
Server : Pool Size :5
Server : ActiveCount :5
Server : TaskCount :9
Server : CompletedTaskCount :0
a new task arrived
Server : Pool Size :5
Server : ActiveCount :5
Server : TaskCount :10
Server : CompletedTaskCount :0
pool-1-thread-4 : Task Task 3 : Finished on : Mon Jul 24 20:40:09 CST 2017
pool-1-thread-4 : Task Task 5 : Created on : Mon Jul 24 20:40:07 CST 2017
pool-1-thread-4 : Task Task 5 : Started on : Mon Jul 24 20:40:09 CST 2017
pool-1-thread-4 : Task Task 5 : Doing a task during 4 seconds
pool-1-thread-3 : Task Task 2 : Finished on : Mon Jul 24 20:40:11 CST 2017
pool-1-thread-3 : Task Task 6 : Created on : Mon Jul 24 20:40:07 CST 2017
pool-1-thread-3 : Task Task 6 : Started on : Mon Jul 24 20:40:11 CST 2017
pool-1-thread-3 : Task Task 6 : Doing a task during 4 seconds
pool-1-thread-5 : Task Task 4 : Finished on : Mon Jul 24 20:40:12 CST 2017
pool-1-thread-5 : Task Task 7 : Created on : Mon Jul 24 20:40:07 CST 2017
pool-1-thread-5 : Task Task 7 : Started on : Mon Jul 24 20:40:12 CST 2017
pool-1-thread-5 : Task Task 7 : Doing a task during 1 seconds
pool-1-thread-5 : Task Task 7 : Finished on : Mon Jul 24 20:40:13 CST 2017
pool-1-thread-5 : Task Task 8 : Created on : Mon Jul 24 20:40:07 CST 2017
pool-1-thread-5 : Task Task 8 : Started on : Mon Jul 24 20:40:13 CST 2017
pool-1-thread-5 : Task Task 8 : Doing a task during 4 seconds
pool-1-thread-4 : Task Task 5 : Finished on : Mon Jul 24 20:40:13 CST 2017
pool-1-thread-4 : Task Task 9 : Created on : Mon Jul 24 20:40:07 CST 2017
pool-1-thread-4 : Task Task 9 : Started on : Mon Jul 24 20:40:13 CST 2017
pool-1-thread-4 : Task Task 9 : Doing a task during 9 seconds
pool-1-thread-2 : Task Task 1 : Finished on : Mon Jul 24 20:40:14 CST 2017
pool-1-thread-3 : Task Task 6 : Finished on : Mon Jul 24 20:40:15 CST 2017
pool-1-thread-1 : Task Task 0 : Finished on : Mon Jul 24 20:40:16 CST 2017
pool-1-thread-5 : Task Task 8 : Finished on : Mon Jul 24 20:40:17 CST 2017
pool-1-thread-4 : Task Task 9 : Finished on : Mon Jul 24 20:40:22 CST 2017
複製程式碼