例子:
//主類
public class Main {
public static void main(String[] args) throws Exception{
BlockingQueue<Data> queue=new LinkedBlockingQueue<Data>(10);
//生產者
Provider p1 = new Provider(queue);
Provider p2 = new Provider(queue);
Provider p3 = new Provider(queue);
//消費者
Consumer c1 = new Consumer(queue);
Consumer c2 = new Consumer(queue);
Consumer c3 = new Consumer(queue);
//創建線程池
ExecutorService cachePool = Executors.newCachedThreadPool();
cachePool.execute(p1);
cachePool.execute(p2);
cachePool.execute(p3);
cachePool.execute(c1);
cachePool.execute(c2);
cachePool.execute(c3);
try {
Thread.sleep(3000);
}catch (InterruptedException e){
e.printStackTrace();
}
p1.stop();
p2.stop();
p3.stop();
try {
Thread.sleep(2000);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
//生產者
public class Provider implements Runnable {
//共享緩存區
private BlockingQueue<Data> queue;
private volatile boolean isRunning =true;
private static AtomicInteger count= new AtomicInteger();
private static Random r = new Random();
public Provider(BlockingQueue queue){
this.queue=queue;
}
@Override
public void run() {
while (isRunning){
try {
Thread.sleep(r.nextInt(1000));
//獲取的數據進行累計
int id = count.incrementAndGet();
//比如通過一個getData方法獲取了
Data data = new Data(Integer.toString(id), "數據" + id);
System.out.println("當前線程:"+Thread.currentThread().getName()+",獲取了數據Id," +data.getId()+
"裝載到queue中去");
//2秒鐘沒有加進去,返回false
if (!this.queue.offer(data,2, TimeUnit.SECONDS)){
System.out.println("提交到Queue數據失敗");
}
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
public void stop(){
this.isRunning=false;
}
}
//消費者
public class Consumer implements Runnable{
private BlockingQueue<Data> queue;
public Consumer(BlockingQueue queue){
this.queue=queue;
}
//隨機對象
private static Random r =new Random();
@Override
public void run() {
while (true){
try {
Data data = this.queue.take();
//模仿數據處理
Thread.sleep(r.nextInt(1000));
System.out.println("當前消費線程:"+Thread.currentThread().getName()+",消費成功" +
"消費數據Id爲:"+data.getId());
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
}
//data類
public class Data {
private String id;
private String name;
public Data(String id,String name){
this.id=id;
this.name=name;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Data{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
'}';
}
}
輸出結果:
當前線程:pool-1-thread-1,獲取了數據Id,1裝載到queue中去
當前線程:pool-1-thread-3,獲取了數據Id,2裝載到queue中去
當前消費線程:pool-1-thread-5,消費成功消費數據Id爲:2
當前線程:pool-1-thread-1,獲取了數據Id,3裝載到queue中去
當前線程:pool-1-thread-3,獲取了數據Id,4裝載到queue中去
當前消費線程:pool-1-thread-5,消費成功消費數據Id爲:4
當前消費線程:pool-1-thread-6,消費成功消費數據Id爲:3
當前線程:pool-1-thread-2,獲取了數據Id,5裝載到queue中去
當前消費線程:pool-1-thread-5,消費成功消費數據Id爲:5
當前消費線程:pool-1-thread-4,消費成功消費數據Id爲:1
當前線程:pool-1-thread-2,獲取了數據Id,6裝載到queue中去
當前線程:pool-1-thread-1,獲取了數據Id,7裝載到queue中去
當前線程:pool-1-thread-3,獲取了數據Id,8裝載到queue中去
當前線程:pool-1-thread-1,獲取了數據Id,9裝載到queue中去
當前線程:pool-1-thread-2,獲取了數據Id,10裝載到queue中去
當前消費線程:pool-1-thread-6,消費成功消費數據Id爲:6
當前線程:pool-1-thread-3,獲取了數據Id,11裝載到queue中去
當前消費線程:pool-1-thread-6,消費成功消費數據Id爲:9
當前線程:pool-1-thread-2,獲取了數據Id,12裝載到queue中去
當前線程:pool-1-thread-1,獲取了數據Id,13裝載到queue中去
當前線程:pool-1-thread-2,獲取了數據Id,14裝載到queue中去
當前消費線程:pool-1-thread-4,消費成功消費數據Id爲:8
當前消費線程:pool-1-thread-5,消費成功消費數據Id爲:7
當前線程:pool-1-thread-2,獲取了數據Id,15裝載到queue中去
當前消費線程:pool-1-thread-4,消費成功消費數據Id爲:11
當前線程:pool-1-thread-2,獲取了數據Id,16裝載到queue中去
當前線程:pool-1-thread-3,獲取了數據Id,17裝載到queue中去
當前消費線程:pool-1-thread-4,消費成功消費數據Id爲:13
當前消費線程:pool-1-thread-6,消費成功消費數據Id爲:10
當前線程:pool-1-thread-2,獲取了數據Id,18裝載到queue中去
當前線程:pool-1-thread-3,獲取了數據Id,19裝載到queue中去
當前消費線程:pool-1-thread-4,消費成功消費數據Id爲:14
當前線程:pool-1-thread-3,獲取了數據Id,20裝載到queue中去
當前線程:pool-1-thread-1,獲取了數據Id,21裝載到queue中去
當前消費線程:pool-1-thread-5,消費成功消費數據Id爲:12
當前消費線程:pool-1-thread-4,消費成功消費數據Id爲:16
當前線程:pool-1-thread-2,獲取了數據Id,22裝載到queue中去
當前消費線程:pool-1-thread-6,消費成功消費數據Id爲:15
當前消費線程:pool-1-thread-5,消費成功消費數據Id爲:17
當前消費線程:pool-1-thread-4,消費成功消費數據Id爲:18
當前消費線程:pool-1-thread-5,消費成功消費數據Id爲:20
當前消費線程:pool-1-thread-6,消費成功消費數據Id爲:19
當前消費線程:pool-1-thread-4,消費成功消費數據Id爲:21
當前消費線程:pool-1-thread-5,消費成功消費數據Id爲:22
Executor框架:
發現都是調用底層的同一個方法ThreadPoolExecutor()
實現自定義線程池:
第一個參數corePoolSize:核心線程
表示線程池初始化的線程數量
第二個參數maxinumPoolSize:線程池最大線程數量
第三四個參數:表示線程執行完之後,多長時間回收 0表示線程執行完立刻回收
第五個參數:任務多了會放在該隊列中
第七個參數:拒絕策略
newScheduledThreadPool:
class Temp extends Thread {
public void run(){
System.out.println("run");
}
}
public class ScheduleJob{
public static void main(String[] args) {
Temp temp = new Temp();
//初始化線程的數量
ScheduledExecutorService schedule = Executors.newScheduledThreadPool(1);
//第二個參數1表示初始化1秒之後去執行的時間,第二個參數表示3秒輪詢
schedule.scheduleWithFixedDelay(temp,1,3, TimeUnit.SECONDS);
}
}
自定義線程池使用詳解:
例子:
1.有界隊列
public class UseThreadPoolExecutor1 {
public static void main(String[] args) {
/**
* 在使用有界隊列時,若有新的任務需要執行,如果線程池實際線程數小於corePoolSize,則優先創建線程,
* 若大於corePoolSize,則會將任務加入隊列,
* 若隊列已滿,則在總線程數不大於maximumPoolSize的前提下,創建新的線程,
* 若線程數大於maximumPoolSize,則執行拒絕策略。或其他自定義方式。
*
*/
ThreadPoolExecutor pool = new ThreadPoolExecutor(
1,//核心線程數量
2,// 最大線程數量
60,//空閒時間
TimeUnit.SECONDS,//空閒時間的單位
new ArrayBlockingQueue<Runnable>(3)//指定一種隊列 (有界隊列)
);
MyTask mt1 = new MyTask(1, "任務1");
MyTask mt2 = new MyTask(2, "任務2");
MyTask mt3 = new MyTask(3, "任務3");
MyTask mt4 = new MyTask(4, "任務4");
MyTask mt5 = new MyTask(5, "任務5");
MyTask mt6 = new MyTask(6, "任務6");
pool.execute(mt1);
pool.execute(mt2);
/* pool.execute(mt3);
pool.execute(mt4);
pool.execute(mt5);*/
// pool.execute(mt6);
pool.shutdown();
}
}
public class MyTask implements Runnable {
private int taskId;
private String taskName;
public MyTask(int taskId, String taskName){
this.taskId = taskId;
this.taskName = taskName;
}
public int getTaskId() {
return taskId;
}
public void setTaskId(int taskId) {
this.taskId = taskId;
}
public String getTaskName() {
return taskName;
}
public void setTaskName(String taskName) {
this.taskName = taskName;
}
@Override
public void run() {
try {
System.out.println("run taskId =" + this.taskId);
Thread.sleep(5*1000);
//System.out.println("end taskId =" + this.taskId);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public String toString(){
return Integer.toString(this.taskId);
}
}
說明:
pool.execute(mt1);
pool.execute(mt2);
pool.shutdown();
運行結果:
run taskId =1
run taskId =2
當放2個任務的時候,因爲核心線程爲1,第二個任務會放在隊列裏面。第一個結果出來之後5秒鐘纔會輸出 run taskId =2 。
pool.execute(mt1);
pool.execute(mt2);
pool.execute(mt3);
pool.execute(mt4);
pool.execute(mt5);
pool.shutdown();
運行結果:
run taskId =1
run taskId =5
run taskId =2
run taskId =3
run taskId =4
放了5個任務已經,初始化一個線程執行一個,隊列裏面放3個 一共4個,超出的一個會另起一個線程。
所以先同時輸出run taskId =1 run taskId =5,5秒後在同時輸出run taskId =2 run taskId =3最後輸出run taskId =4
pool.execute(mt1);
pool.execute(mt2);
pool.execute(mt3);
pool.execute(mt4);
pool.execute(mt5);
pool.execute(mt6);
pool.shutdown();
放了6個任務,隊列滿了,而且超出線程池最大線程數量。會執行拒絕策略。第6個任務會拋出異常。
2.無界隊列
package com.bjsxt.height.concurrent018;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class UseThreadPoolExecutor2 implements Runnable{
private static AtomicInteger count = new AtomicInteger(0);
@Override
public void run() {
try {
int temp = count.incrementAndGet();
System.out.println("任務" + temp);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception{
//System.out.println(Runtime.getRuntime().availableProcessors());
BlockingQueue<Runnable> queue =
new LinkedBlockingQueue<Runnable>();
//new ArrayBlockingQueue<Runnable>(10);
ExecutorService executor = new ThreadPoolExecutor(
5, //core
10, //max
120L, //2fenzhong
TimeUnit.SECONDS,
queue);
for(int i = 0 ; i < 20; i++){
executor.execute(new UseThreadPoolExecutor2());
}
Thread.sleep(1000);
System.out.println("queue size:" + queue.size()); //10
Thread.sleep(2000);
}
}
輸出結果:
任務2
任務1
任務3
任務4
任務5
queue size:15
任務6
任務7
任務8
任務10
任務9
任務11
任務12
任務13
任務15
任務14
任務16
任務17
任務18
任務20
任務19
說明:會5個5個的執行
策略:
public class UseThreadPoolExecutor1 {
public static void main(String[] args) {
/**
* 在使用有界隊列時,若有新的任務需要執行,如果線程池實際線程數小於corePoolSize,則優先創建線程,
* 若大於corePoolSize,則會將任務加入隊列,
* 若隊列已滿,則在總線程數不大於maximumPoolSize的前提下,創建新的線程,
* 若線程數大於maximumPoolSize,則執行拒絕策略。或其他自定義方式。
*
*/
ThreadPoolExecutor pool = new ThreadPoolExecutor(
1, //coreSize
2, //MaxSize
60, //60
TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(3) //指定一種隊列 (有界隊列)
//new LinkedBlockingQueue<Runnable>()
// , new MyRejected()
, new ThreadPoolExecutor.DiscardOldestPolicy()
);
MyTask mt1 = new MyTask(1, "任務1");
MyTask mt2 = new MyTask(2, "任務2");
MyTask mt3 = new MyTask(3, "任務3");
MyTask mt4 = new MyTask(4, "任務4");
MyTask mt5 = new MyTask(5, "任務5");
MyTask mt6 = new MyTask(6, "任務6");
pool.execute(mt1);
pool.execute(mt2);
pool.execute(mt3);
pool.execute(mt4);
pool.execute(mt5);
pool.execute(mt6);
pool.shutdown();
}
}
DiscardOldestPolicy丟棄最老的任務
輸出結果:
run taskId =1
run taskId =5
run taskId =3
run taskId =4
run taskId =6
丟棄了任務2.。。
可以自定義策略:
例子:
public class UseThreadPoolExecutor1 {
public static void main(String[] args) {
/**
* 在使用有界隊列時,若有新的任務需要執行,如果線程池實際線程數小於corePoolSize,則優先創建線程,
* 若大於corePoolSize,則會將任務加入隊列,
* 若隊列已滿,則在總線程數不大於maximumPoolSize的前提下,創建新的線程,
* 若線程數大於maximumPoolSize,則執行拒絕策略。或其他自定義方式。
*
*/
ThreadPoolExecutor pool = new ThreadPoolExecutor(
1, //coreSize
2, //MaxSize
60, //60
TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(3) //指定一種隊列 (有界隊列)
//new LinkedBlockingQueue<Runnable>()
, new MyRejected()
// , new ThreadPoolExecutor.DiscardOldestPolicy()
);
MyTask mt1 = new MyTask(1, "任務1");
MyTask mt2 = new MyTask(2, "任務2");
MyTask mt3 = new MyTask(3, "任務3");
MyTask mt4 = new MyTask(4, "任務4");
MyTask mt5 = new MyTask(5, "任務5");
MyTask mt6 = new MyTask(6, "任務6");
pool.execute(mt1);
pool.execute(mt2);
pool.execute(mt3);
pool.execute(mt4);
pool.execute(mt5);
pool.execute(mt6);
pool.shutdown();
}
}
//拒絕的類
public class MyRejected implements RejectedExecutionHandler{
public MyRejected(){
}
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
System.out.println("自定義處理..");
System.out.println("當前被拒絕任務爲:" + r.toString());
}
}
實現了RejectedExecutionHandler接口
運行結果:
自定義處理…
run taskId =1
run taskId =5
當前被拒絕任務爲:6
run taskId =2
run taskId =3
run taskId =4
可以在自定義策略裏http請求返回給任務提交者,或者保存到日誌,再次在後臺統一處理比如跑批處理