import java.util.Vector;
public class SimpleThreadPool {
/* 線程池中的 Trhead 數量 */
private static final Integer NTHREADS = 3;
/* 線程池實例 */
private static SimpleThreadPool threadPool;
private Vector<PThread> pthreads = new Vector<>();
private Vector<Runnable> runnables = new Vector<>();
/* 初始化線程池 */
private SimpleThreadPool() {
for (int i = 0; i < NTHREADS; ++i)
pthreads.add(new PThread(i));
for (PThread pthread : pthreads)
pthread.start();
}
/* 簡單的單例模式線程池 */
public static synchronized SimpleThreadPool getInstance() {
if (threadPool == null)
threadPool = new SimpleThreadPool();
return threadPool;
}
/*
* 向線程池提交一個任務(runnable, 或task)
* 並且喚醒池中的一個睡眠線程,
*
* 如果線程池中沒有空閒線程, 這個notify信號將會"丟失".
* 但是這不影響線程池的功能,
* 因爲當一個線程結束任務的時候, 它會主動檢查任務隊列(runnables), 以查看是否有掛起的任務
*
* 這個地方, runnables.size() 實際上爲我們提供了一個 "喚醒信號計數器", 裏面記錄了喚醒信號的數目,
* 所以, 嚴格地說, 其實喚醒信號並不會丟失.
*
* 這是一種常見的多線程模式:
* 1. 爲喚醒信號提供一個計數器
* 2. 線程睡眠之前總是先檢查喚醒信號計數器
*/
public void submit(Runnable runnable) {
synchronized (runnables) {
System.out.printf("summit runnable %d.\n", ((SimpleRunnable)runnable).getID());
runnables.add(runnable);
runnables.notify();
}
}
/* 線程池中的工作線程
*
* 這些線程完成其任務後不會退出, 而是馬不停蹄地執行任務隊列(runnables)中的下一個任務,
* 如果任務隊列中沒有任務, 那麼此線程將主動睡眠, 直到新的任務到來, 並將其喚醒.
*/
class PThread extends Thread {
private Integer id;
public PThread(Integer id) {
this.id = id;
}
@Override
public void run() {
Runnable runnable;
/*
* 如果要實現線程池的銷燬功能, 請在線程池中額外實現一個變量, 比如disabled,
* 然後將while(true)替換爲while(!disabled);
*/
while (true) {
synchronized (runnables) {
/*
* 被喚醒的工作線程將重新檢查當初導致其阻塞的條件,
* 考慮到以下過程, 這是非常必要的.
*
* 1. 線程0被創建, 發現runnables.empty()==ture, 睡眠
* 2. 一個任務, 比如任務0, 被插入到任務隊列(runnables), 向睡眠的線程發送信號.
* 3. 線程1被創建, 發現runnables.size()==1, 刪除這個任務, 因爲線程1隨後就要執行這個任務
* 4. 線程0被第(2)步中的信號喚醒, 此時任務0已經被線程1執行.
*
* 考慮第(4)步, 如果線程0醒來後不檢查 睡眠條件, 那麼線程0再次執行任務0, 導致不可知的行爲.
*/
while (runnables == null || runnables.isEmpty()) {
try {
System.out.printf("Thread#%d going to sleep.\n", id);
runnables.wait();
} catch (InterruptedException ie) {
}
}
runnable = runnables.remove(0);
}
/* 小細節: 在外部執行任務 */
System.out.printf("Thread#%d waking up with runnable#%d\n", id, ((SimpleRunnable)runnable).getID());
runnable.run();
}
}
}
/* 測試 */
public static void main(String args[]) throws InterruptedException {
Thread.sleep(100);
for (int i = 0; i < 10; ++i) {
SimpleThreadPool.getInstance().submit(new SimpleRunnable(i));
Thread.sleep(100);
}
}
/* 測試 */
static class SimpleRunnable implements Runnable {
private Integer id;
public SimpleRunnable(Integer id) {
this.id = id;
}
public Integer getID() {
return id;
}
@Override
public void run() {
System.out.printf("Runnable #%d passing by.\n", id);
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.printf("Runnable #%d quit.\n", id);
}
}
}
一個簡單的java線程池
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.