javaforthread
『壹』 java實現通用線程池
線程池通俗的描述就是預先創建若干空閑線程 等到需要用多線程去處理事務的時候去喚醒某些空閑線程執行處理任務 這樣就省去了頻繁創建線程的時間 因為頻 繁創建線程是要耗費大量的CPU資源的 如果一個應用程序需要頻繁地處理大量並發事務 不斷的創建銷毀線程往往會大大地降低系統的效率 這時候線程池就派 上用場了
本文旨在使用Java語言編寫一個通用的線程池 當需要使用線程池處理事務時 只需按照指定規范封裝好事務處理對象 然後用已有的線程池對象去自動選擇空 閑線程自動調用事務處理對象即可 並實現線程池的動態修改(修改當前線程數 最大線程數等) 下面是實現代碼
//ThreadTask java
package polarman threadpool;
/** *//**
*線程任務
* @author ryang
*
*/
public interface ThreadTask {
public void run();
}
//PooledThread java
package polarman threadpool;
import java util Collection; import java util Vector;
/** *//**
*接受線程池管理的線程
* @author ryang
*
*/
public class PooledThread extends Thread {
protected Vector tasks = new Vector();
protected boolean running = false;
protected boolean stopped = false;
protected boolean paused = false;
protected boolean killed = false;
private ThreadPool pool;
public PooledThread(ThreadPool pool) { this pool = pool;
}
public void putTask(ThreadTask task) { tasks add(task);
}
public void putTasks(ThreadTask[] tasks) { for(int i= ; i<tasks length; i++) this tasks add(tasks[i]);
}
public void putTasks(Collection tasks) { this tasks addAll(tasks);
}
protected ThreadTask popTask() { if(tasks size() > ) return (ThreadTask)tasks remove( );
else
return null;
}
public boolean isRunning() {
return running;
}
public void stopTasks() {
stopped = true;
}
public void stopTasksSync() {
stopTasks();
while(isRunning()) { try {
sleep( );
} catch (InterruptedException e) {
}
}
}
public void pauseTasks() {
paused = true;
}
public void pauseTasksSync() {
pauseTasks();
while(isRunning()) { try {
sleep( );
} catch (InterruptedException e) {
}
}
}
public void kill() { if(!running)
interrupt();
else
killed = true;
}
public void killSync() {
kill();
while(isAlive()) { try {
sleep( );
} catch (InterruptedException e) {
}
}
}
public synchronized void startTasks() {
running = true;
this notify();
}
public synchronized void run() { try { while(true) { if(!running || tasks size() == ) { pool notifyForIdleThread(); //System out println(Thread currentThread() getId() + : 空閑 ); this wait(); }else {
ThreadTask task;
while((task = popTask()) != null) { task run(); if(stopped) {
stopped = false;
if(tasks size() > ) { tasks clear(); System out println(Thread currentThread() getId() + : Tasks are stopped );
break;
}
}
if(paused) {
paused = false;
if(tasks size() > ) { System out println(Thread currentThread() getId() + : Tasks are paused );
break;
}
}
}
running = false;
}
if(killed) {
killed = false;
break;
}
}
}catch(InterruptedException e) {
return;
}
//System out println(Thread currentThread() getId() + : Killed );
}
}
//ThreadPool java
package polarman threadpool;
import java util Collection; import java util Iterator; import java util Vector;
/** *//**
*線程池
* @author ryang
*
*/
public class ThreadPool {
protected int maxPoolSize;
protected int initPoolSize;
protected Vector threads = new Vector();
protected boolean initialized = false;
protected boolean hasIdleThread = false;
public ThreadPool(int maxPoolSize int initPoolSize) { this maxPoolSize = maxPoolSize; this initPoolSize = initPoolSize;
}
public void init() {
initialized = true;
for(int i= ; i<initPoolSize; i++) {
PooledThread thread = new PooledThread(this);
thread start(); threads add(thread);
}
//System out println( 線程池初始化結束 線程數= + threads size() + 最大線程數= + maxPoolSize);
}
public void setMaxPoolSize(int maxPoolSize) { //System out println( 重設最大線程數 最大線程數= + maxPoolSize); this maxPoolSize = maxPoolSize;
if(maxPoolSize < getPoolSize())
setPoolSize(maxPoolSize);
}
/** *//**
*重設當前線程數
* 若需殺掉某線程 線程不會立刻殺掉 而會等到線程中的事務處理完成* 但此方法會立刻從線程池中移除該線程 不會等待事務處理結束
* @param size
*/
public void setPoolSize(int size) { if(!initialized) {
initPoolSize = size;
return;
}else if(size > getPoolSize()) { for(int i=getPoolSize(); i<size && i<maxPoolSize; i++) {
PooledThread thread = new PooledThread(this);
thread start(); threads add(thread);
}
}else if(size < getPoolSize()) { while(getPoolSize() > size) { PooledThread th = (PooledThread)threads remove( ); th kill();
}
}
//System out println( 重設線程數 線程數= + threads size());
}
public int getPoolSize() { return threads size();
}
protected void notifyForIdleThread() {
hasIdleThread = true;
}
protected boolean waitForIdleThread() {
hasIdleThread = false;
while(!hasIdleThread && getPoolSize() >= maxPoolSize) { try { Thread sleep( ); } catch (InterruptedException e) {
return false;
}
}
return true;
}
public synchronized PooledThread getIdleThread() { while(true) { for(Iterator itr=erator(); itr hasNext();) { PooledThread th = (PooledThread)itr next(); if(!th isRunning())
return th;
}
if(getPoolSize() < maxPoolSize) {
PooledThread thread = new PooledThread(this);
thread start(); threads add(thread);
return thread;
}
//System out println( 線程池已滿 等待 );
if(waitForIdleThread() == false)
return null;
}
}
public void processTask(ThreadTask task) {
PooledThread th = getIdleThread();
if(th != null) { th putTask(task); th startTasks();
}
}
public void processTasksInSingleThread(ThreadTask[] tasks) {
PooledThread th = getIdleThread();
if(th != null) { th putTasks(tasks); th startTasks();
}
}
public void processTasksInSingleThread(Collection tasks) {
PooledThread th = getIdleThread();
if(th != null) { th putTasks(tasks); th startTasks();
}
}
}
下面是線程池的測試程序
//ThreadPoolTest java
import java io BufferedReader; import java io IOException; import java io InputStreamReader;
import polarman threadpool ThreadPool; import polarman threadpool ThreadTask;
public class ThreadPoolTest {
public static void main(String[] args) { System out println( quit 退出 ); System out println( task A 啟動任務A 時長為 秒 ); System out println( size 設置當前線程池大小為 ); System out println( max 設置線程池最大線程數為 ); System out println();
final ThreadPool pool = new ThreadPool( ); pool init();
Thread cmdThread = new Thread() { public void run() {
BufferedReader reader = new BufferedReader(new InputStreamReader(System in));
while(true) { try { String line = reader readLine(); String words[] = line split( ); if(words[ ] equalsIgnoreCase( quit )) { System exit( ); }else if(words[ ] equalsIgnoreCase( size ) && words length >= ) { try { int size = Integer parseInt(words[ ]); pool setPoolSize(size); }catch(Exception e) {
}
}else if(words[ ] equalsIgnoreCase( max ) && words length >= ) { try { int max = Integer parseInt(words[ ]); pool setMaxPoolSize(max); }catch(Exception e) {
}
}else if(words[ ] equalsIgnoreCase( task ) && words length >= ) { try { int timelen = Integer parseInt(words[ ]); SimpleTask task = new SimpleTask(words[ ] timelen * ); pool processTask(task); }catch(Exception e) {
}
}
} catch (IOException e) { e printStackTrace();
}
}
}
};
cmdThread start();
/**//*
for(int i= ; i< ; i++){
SimpleTask task = new SimpleTask( Task + i (i+ )* ); pool processTask(task);
}*/
}
}
class SimpleTask implements ThreadTask {
private String taskName;
private int timeLen;
public SimpleTask(String taskName int timeLen) { this taskName = taskName; this timeLen = timeLen;
}
public void run() { System out println(Thread currentThread() getId() +
: START TASK + taskName + );
try { Thread sleep(timeLen); } catch (InterruptedException e) {
}
System out println(Thread currentThread() getId() +
: END TASK + taskName + );
}
}
使用此線程池相當簡單 下面兩行代碼初始化線程池
ThreadPool pool = new ThreadPool( ); pool init();
要處理的任務實現ThreadTask 介面即可(如測試代碼里的SimpleTask) 這個介面只有一個方法run()
兩行代碼即可調用
lishixin/Article/program/Java/hx/201311/27203
『貳』 Java多線程程序設計詳細解析
一、理解多線程
多線程是這樣一種機制,它允許在程序中並發執行多個指令流,每個指令流都稱為一個線程,彼此間互相獨立。
線程又稱為輕量級進程,它和進程一樣擁有獨立的執行控制,由操作系統負責調度,區別在於線程沒有獨立的存儲空間,而是和所屬進程中的其它線程共享一個存儲空間,這使得線程間的通信遠較進程簡單。
多個線程的執行是並發的,也就是在邏輯上「同時」,而不管是否是物理上的「同時」。如果系統只有一個CPU,那麼真正的「同時」是不可能的,但是由於CPU的速度非常快,用戶感覺不到其中的區別,因此我們也不用關心它,只需要設想各個線程是同時執行即可。
多線程和傳統的單線程在程序設計上最大的區別在於,由於各個線程的控制流彼此獨立,使得各個線程之間的代碼是亂序執行的,由此帶來的線程調度,同步等問題,將在以後探討。
二、在Java中實現多線凱液慎程
我們不妨設想,為了創建一個新的線程,我們需要做些什麼?很顯然,我們必須指明這個線程所要執行的代碼,而這就是在Java中實現多線程我們所需要做的一切!
真是神奇!Java是如何做到這一點的?通過類!作為一個完全面向對象的語言,Java提供了類java.lang.Thread來方便多線程編程,這個類提供了大量的方法來方便我們控制自己的各個線程,我們以後的討論都將圍繞這個類進行。
那麼如何提供給 Java 我們要線程執行的代碼呢?讓我們來看一看 Thread 類。Thread 類最重要的方法是run(),它為Thread類的方法start()所調用,提供我們的線程所要執行的代碼。為了指定我們自己的代碼,只需要覆蓋它!
方法一:繼承 Thread 類,覆蓋方法 run(),我們在創建的 Thread 類的子類中重寫 run() ,加入線程所要執行的代碼即可。下面是一個例子:
public class MyThread extends Thread
{
int count= 1, number;
public MyThread(int num)
{
number = num;
System.out.println
("創建線程 " + number);
}
public void run() {
while(true) {
System.out.println
("線程 " + number + ":計數 " + count);
if(++count== 6) return;
}
}
public static void main(String args[])
{
for(int i = 0;
i 〈 5; i++) new MyThread(i+1).start();
}
}
這種方法簡單明了,符合大家的習慣,但是,它也有一個很大的缺點,那就是如果我們的類已經從一個類繼承(如小程序必須繼承自 Applet 類),則無法再繼承 Thread 類,這時如果我們又不想建立一個新的類,應該怎麼辦呢?
我們不妨來探索一種新的方法:我們不創建Thread類的子類,而是直接使用它,那麼我們只能將我們的方法作為參數傳遞給 Thread 類的實例,有點類似回調函數。但是 Java 沒有指針,我們只能傳遞一個包含這個方法的類的實例。
那麼如何限制這個類盯敬必須包含這一方法呢?當然是使用介面!(雖然抽象類也可滿足,但是需要繼承,而我們之所以要採用這種新方法,不就是為了避免繼承帶來的限制嗎?)
Java 提供了介面 java.lang.Runnable 來支持這種方法。
方法二:實現 Runnable 介面
Runnable介面只有一個方法run(),我們聲明自己的類實現Runnable介面並提供這一方法,將我們的線程代碼寫入其中,就完成了這一部分的任務。但是Runnable介面並沒有任何對線程的支持,我們還必須創建Thread類的實例,這一點通過Thread類的構造函數public Thread(Runnable target);來實現。下面埋禪是一個例子:
public class MyThread implements Runnable
{
int count= 1, number;
public MyThread(int num)
{
number = num;
System.out.println("創建線程 " + number);
}
public void run()
{
while(true)
{
System.out.println
("線程 " + number + ":計數 " + count);
if(++count== 6) return;
}
}
public static void main(String args[])
{
for(int i = 0; i 〈 5;
i++) new Thread(new MyThread(i+1)).start();
}
}
嚴格地說,創建Thread子類的實例也是可行的,但是必須注意的是,該子類必須沒有覆蓋 Thread 類的 run 方法,否則該線程執行的將是子類的 run 方法,而不是我們用以實現Runnable 介面的類的 run 方法,對此大家不妨試驗一下。
使用 Runnable 介面來實現多線程使得我們能夠在一個類中包容所有的代碼,有利於封裝,它的缺點在於,我們只能使用一套代碼,若想創建多個線程並使各個線程執行不同的代碼,則仍必須額外創建類,如果這樣的話,在大多數情況下也許還不如直接用多個類分別繼承 Thread 來得緊湊。
綜上所述,兩種方法各有千秋,大家可以靈活運用。
下面讓我們一起來研究一下多線程使用中的一些問題。
三、線程的四種狀態
1. 新狀態:線程已被創建但尚未執行(start() 尚未被調用)。
2. 可執行狀態:線程可以執行,雖然不一定正在執行。CPU 時間隨時可能被分配給該線程,從而使得它執行。
3. 死亡狀態:正常情況下 run() 返回使得線程死亡。調用 stop()或 destroy() 亦有同樣效果,但是不被推薦,前者會產生異常,後者是強制終止,不會釋放鎖。
4. 阻塞狀態:線程不會被分配 CPU 時間,無法執行。
四、線程的優先順序
線程的優先順序代表該線程的重要程度,當有多個線程同時處於可執行狀態並等待獲得 CPU 時間時,線程調度系統根據各個線程的優先順序來決定給誰分配 CPU 時間,優先順序高的線程有更大的機會獲得 CPU 時間,優先順序低的線程也不是沒有機會,只是機會要小一些罷了。
你可以調用 Thread 類的方法 getPriority() 和 setPriority()來存取線程的優先順序,線程的優先順序界於1(MIN_PRIORITY)和10(MAX_PRIORITY)之間,預設是5(NORM_PRIORITY)。
五、線程的同步
由於同一進程的多個線程共享同一片存儲空間,在帶來方便的同時,也帶來了訪問沖突這個嚴重的問題。Java語言提供了專門機制以解決這種沖突,有效避免了同一個數據對象被多個線程同時訪問。
由於我們可以通過 private 關鍵字來保證數據對象只能被方法訪問,所以我們只需針對方法提出一套機制,這套機制就是 synchronized 關鍵字,它包括兩種用法:synchronized 方法和 synchronized 塊。
1. synchronized 方法:通過在方法聲明中加入 synchronized關鍵字來聲明 synchronized 方法。如:
public synchronized void accessVal(int newVal);
synchronized 方法控制對類成員變數的訪問:每個類實例對應一把鎖,每個 synchronized 方法都必須獲得調用該方法的類實例的鎖方能執行,否則所屬線程阻塞,方法一旦執行,就獨占該鎖,直到從該方法返回時才將鎖釋放,此後被阻塞的線程方能獲得該鎖,重新進入可執行狀態。
這種機制確保了同一時刻對於每一個類實例,其所有聲明為 synchronized 的成員函數中至多隻有一個處於可執行狀態(因為至多隻有一個能夠獲得該類實例對應的鎖),從而有效避免了類成員變數的訪問沖突(只要所有可能訪問類成員變數的方法均被聲明為 synchronized)。
在 Java 中,不光是類實例,每一個類也對應一把鎖,這樣我們也可將類的靜態成員函數聲明為 synchronized ,以控制其對類的靜態成員變數的訪問。
synchronized 方法的缺陷:若將一個大的方法聲明為synchronized 將會大大影響效率,典型地,若將線程類的方法 run() 聲明為 synchronized ,由於在線程的整個生命期內它一直在運行,因此將導致它對本類任何 synchronized 方法的調用都永遠不會成功。當然我們可以通過將訪問類成員變數的代碼放到專門的方法中,將其聲明為 synchronized ,並在主方法中調用來解決這一問題,但是 Java 為我們提供了更好的解決辦法,那就是 synchronized 塊。
2. synchronized 塊:通過 synchronized關鍵字來聲明synchronized 塊。語法如下:
synchronized(syncObject)
{
//允許訪問控制的代碼
}
#p#副標題#e#
synchronized 塊是這樣一個代碼塊,其中的代碼必須獲得對象 syncObject (如前所述,可以是類實例或類)的鎖方能執行,具體機制同前所述。由於可以針對任意代碼塊,且可任意指定上鎖的對象,故靈活性較高。
六、線程的阻塞為了解決對共享存儲區的訪問沖突,Java 引入了同步機制,現在讓我們來考察多個線程對共享資源的訪問,顯然同步機制已經不夠了,因為在任意時刻所要求的資源不一定已經准備好了被訪問,反過來,同一時刻准備好了的資源也可能不止一個。為了解決這種情況下的訪問控制問題,Java 引入了對阻塞機制的支持。
阻塞指的是暫停一個線程的執行以等待某個條件發生(如某資源就緒),學過操作系統的同學對它一定已經很熟悉了。Java 提供了大量方法來支持阻塞,下面讓我們逐一分析。
1. sleep() 方法:sleep() 允許 指定以毫秒為單位的一段時間作為參數,它使得線程在指定的時間內進入阻塞狀態,不能得到CPU 時間,指定的時間一過,線程重新進入可執行狀態。典型地,sleep() 被用在等待某個資源就緒的情形:測試發現條件不滿足後,讓線程阻塞一段時間後重新測試,直到條件滿足為止。
2. suspend() 和 resume() 方法:兩個方法配套使用,suspend()使得線程進入阻塞狀態,並且不會自動恢復,必須其對應的resume() 被調用,才能使得線程重新進入可執行狀態。典型地,suspend() 和 resume() 被用在等待另一個線程產生的結果的情形:測試發現結果還沒有產生後,讓線程阻塞,另一個線程產生了結果後,調用 resume() 使其恢復。
3. yield() 方法:yield() 使得線程放棄當前分得的 CPU 時間,但是不使線程阻塞,即線程仍處於可執行狀態,隨時可能再次分得 CPU 時間。調用 yield() 的效果等價於調度程序認為該線程已執行了足夠的時間從而轉到另一個線程。
4. wait() 和 notify() 方法:兩個方法配套使用,wait() 使得線程進入阻塞狀態,它有兩種形式,一種允許 指定以毫秒為單位的一段時間作為參數,另一種沒有參數,前者當對應的 notify() 被調用或者超出指定時間時線程重新進入可執行狀態,後者則必須對應的 notify() 被調用。
初看起來它們與 suspend() 和 resume() 方法對沒有什麼分別,但是事實上它們是截然不同的。區別的核心在於,前面敘述的所有方法,阻塞時都不會釋放佔用的鎖(如果佔用了的話),而這一對方法則相反。
上述的核心區別導致了一系列的細節上的區別。
首先,前面敘述的所有方法都隸屬於 Thread 類,但是這一對卻直接隸屬於 Object 類,也就是說,所有對象都擁有這一對方法。初看起來這十分不可思議,但是實際上卻是很自然的,因為這一對方法阻塞時要釋放佔用的鎖,而鎖是任何對象都具有的,調用任意對象的 wait() 方法導致線程阻塞,並且該對象上的鎖被釋放。
而調用 任意對象的notify()方法則導致因調用該對象的 wait() 方法而阻塞的線程中隨機選擇的一個解除阻塞(但要等到獲得鎖後才真正可執行)。
其次,前面敘述的所有方法都可在任何位置調用,但是這一對方法卻必須在 synchronized 方法或塊中調用,理由也很簡單,只有在synchronized 方法或塊中當前線程才佔有鎖,才有鎖可以釋放。
同樣的道理,調用這一對方法的對象上的鎖必須為當前線程所擁有,這樣才有鎖可以釋放。因此,這一對方法調用必須放置在這樣的 synchronized 方法或塊中,該方法或塊的上鎖對象就是調用這一對方法的對象。若不滿足這一條件,則程序雖然仍能編譯,但在運行時會出現IllegalMonitorStateException 異常。
wait() 和 notify() 方法的上述特性決定了它們經常和synchronized 方法或塊一起使用,將它們和操作系統的進程間通信機製作一個比較就會發現它們的相似性:synchronized方法或塊提供了類似於操作系統原語的功能,它們的執行不會受到多線程機制的干擾,而這一對方法則相當於 block 和wakeup 原語(這一對方法均聲明為 synchronized)。
它們的結合使得我們可以實現操作系統上一系列精妙的進程間通信的演算法(如信號量演算法),並用於解決各種復雜的線程間通信問題。
關於 wait() 和 notify() 方法最後再說明兩點:
第一:調用 notify() 方法導致解除阻塞的線程是從因調用該對象的 wait() 方法而阻塞的線程中隨機選取的,我們無法預料哪一個線程將會被選擇,所以編程時要特別小心,避免因這種不確定性而產生問題。
第二:除了 notify(),還有一個方法 notifyAll() 也可起到類似作用,唯一的區別在於,調用 notifyAll() 方法將把因調用該對象的 wait() 方法而阻塞的所有線程一次性全部解除阻塞。當然,只有獲得鎖的那一個線程才能進入可執行狀態。
談到阻塞,就不能不談一談死鎖,略一分析就能發現,suspend() 方法和不指定超時期限的 wait() 方法的調用都可能產生死鎖。遺憾的是,Java 並不在語言級別上支持死鎖的避免,我們在編程中必須小心地避免死鎖。
以上我們對 Java 中實現線程阻塞的各種方法作了一番分析,我們重點分析了 wait() 和 notify()方法,因為它們的功能最強大,使用也最靈活,但是這也導致了它們的效率較低,較容易出錯。實際使用中我們應該靈活使用各種方法,以便更好地達到我們的目的。
七、守護線程
守護線程是一類特殊的線程,它和普通線程的區別在於它並不是應用程序的核心部分,當一個應用程序的所有非守護線程終止運行時,即使仍然有守護線程在運行,應用程序也將終止,反之,只要有一個非守護線程在運行,應用程序就不會終止。守護線程一般被用於在後台為其它線程提供服務。
可以通過調用方法 isDaemon() 來判斷一個線程是否是守護線程,也可以調用方法 setDaemon() 來將一個線程設為守護線程。
八、線程組
線程組是一個 Java 特有的概念,在 Java 中,線程組是類ThreadGroup 的對象,每個線程都隸屬於唯一一個線程組,這個線程組在線程創建時指定並在線程的整個生命期內都不能更改。
你可以通過調用包含 ThreadGroup 類型參數的 Thread 類構造函數來指定線程屬的線程組,若沒有指定,則線程預設地隸屬於名為 system 的系統線程組。
在 Java 中,除了預建的系統線程組外,所有線程組都必須顯式創建。在 Java 中,除系統線程組外的每個線程組又隸屬於另一個線程組,你可以在創建線程組時指定其所隸屬的線程組,若沒有指定,則預設地隸屬於系統線程組。這樣,所有線程組組成了一棵以系統線程組為根的樹。
Java 允許我們對一個線程組中的所有線程同時進行操作,比如我們可以通過調用線程組的相應方法來設置其中所有線程的優先順序,也可以啟動或阻塞其中的所有線程。
Java 的線程組機制的另一個重要作用是線程安全。線程組機制允許我們通過分組來區分有不同安全特性的線程,對不同組的線程進行不同的處理,還可以通過線程組的分層結構來支持不對等安全措施的採用。
Java 的 ThreadGroup 類提供了大量的方法來方便我們對線程組樹中的每一個線程組以及線程組中的每一個線程進行操作。
九、總結
在本文中,我們講述了 Java 多線程編程的方方面面,包括創建線程,以及對多個線程進行調度、管理。我們深刻認識到了多線程編程的復雜性,以及線程切換開銷帶來的多線程程序的低效性,這也促使我們認真地思考一個問題:我們是否需要多線程?何時需要多線程?
多線程的核心在於多個代碼塊並發執行,本質特點在於各代碼塊之間的代碼是亂序執行的。我們的程序是否需要多線程,就是要看這是否也是它的內在特點。
假如我們的程序根本不要求多個代碼塊並發執行,那自然不需要使用多線程;假如我們的程序雖然要求多個代碼塊並發執行,但是卻不要求亂序,則我們完全可以用一個循環來簡單高效地實現,也不需要使用多線程;只有當它完全符合多線程的特點時,多線程機制對線程間通信和線程管理的強大支持才能有用武之地,這時使用多線程才是值得的。
#p#副標題#e#
『叄』 java for循環中創建線程池
首先要明確線程池的意思,就是線程預先創建好放在一個池裡面,使用後不會銷毀
要區分任務和線程池,任務可以不斷添加,但是線程池裡線程的個數是固定的,當任務數超過線程數後,後面的任務需要等待有空閑的線程才會執行
所以不斷添加任務沒有關系,如果池中有50個線程,你添加100個任務同一時間也只會執行50個任務,剩下的50個任務需要等待前面的任務執行完畢後繼續執行
所以你的主線程原則上可以不斷for,但是你總得有個結束點吧
『肆』 java編程:我想在一個java類里的一個for循環中加入一個睡眠,睡眠時間5分鍾,該怎麼編碼
public static void main(String[] args) {
for(int i = 0; i < 300; i++){
try {
Thread.sleep(1000);//睡眠1秒。循環300次就是300秒也就是五分鍾
System.out.println(i);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
『伍』 鑳借В閲婁竴涓媕ava鐨勭嚎紼嬬殑浣跨敤
闅忕潃璁$畻鏈虹殑椋為熷彂灞曪紝涓浜鴻$畻鏈轟笂鐨勬搷浣滅郴緇熶篃綰風悍閲囩敤澶氫換鍔″拰鍒嗘椂璁捐★紝灝嗘棭鏈熷彧鏈夊ぇ鍨嬭$畻鏈烘墠鍏鋒湁鐨勭郴緇熺壒鎬у甫鍒頒簡涓浜鴻$畻鏈虹郴緇熶腑銆備竴鑸鍙浠ュ湪鍚屼竴鏃墮棿鍐呮墽琛屽氫釜紼嬪簭鐨勬搷浣滅郴緇熼兘鏈夎繘紼嬬殑姒傚康銆備竴涓榪涚▼灝辨槸涓涓鎵ц屼腑鐨勭▼搴忥紝鑰屾瘡涓涓榪涚▼閮芥湁鑷宸辯嫭絝嬬殑涓鍧楀唴瀛樼┖闂淬佷竴緇勭郴緇熻祫婧愩傚湪榪涚▼姒傚康涓錛屾瘡涓涓榪涚▼鐨勫唴閮ㄦ暟鎹鍜岀姸鎬侀兘鏄瀹屽叏鐙絝嬬殑銆侸ava紼嬪簭閫氳繃嫻佹帶鍒舵潵鎵ц岀▼搴忔祦錛岀▼搴忎腑鍗曚釜欏哄簭鐨勬祦鎺у埗縐頒負綰跨▼錛屽氱嚎紼嬪垯鎸囩殑鏄鍦ㄥ崟涓紼嬪簭涓鍙浠ュ悓鏃惰繍琛屽氫釜涓嶅悓鐨勭嚎紼嬶紝鎵ц屼笉鍚岀殑浠誨姟銆傚氱嚎紼嬫剰鍛崇潃涓涓紼嬪簭鐨勫氳岃鍙ュ彲浠ョ湅涓婂幓鍑犱箮鍦ㄥ悓涓鏃墮棿鍐呭悓鏃惰繍琛屻
綰跨▼涓庤繘紼嬬浉浼礆紝鏄涓孌靛畬鎴愭煇涓鐗瑰畾鍔熻兘鐨勪唬鐮侊紝鏄紼嬪簭涓鍗曚釜欏哄簭鐨勬祦鎺у埗錛涗絾涓庤繘紼嬩笉鍚岀殑鏄錛屽悓綾葷殑澶氫釜綰跨▼鏄鍏變韓涓鍧楀唴瀛樼┖闂村拰涓緇勭郴緇熻祫婧愶紝鑰岀嚎紼嬫湰韜鐨勬暟鎹閫氬父鍙鏈夊井澶勭悊鍣ㄧ殑瀵勫瓨鍣ㄦ暟鎹錛屼互鍙婁竴涓渚涚▼搴忔墽琛屾椂浣跨敤鐨勫爢鏍堛傛墍浠ョ郴緇熷湪浜х敓涓涓綰跨▼錛屾垨鑰呭湪鍚勪釜綰跨▼涔嬮棿鍒囨崲鏃訛紝璐熸媴瑕佹瘮榪涚▼灝忕殑澶氾紝姝e洜濡傛わ紝綰跨▼琚縐頒負杞昏礋鑽瘋繘紼嬶紙light-weight process錛夈備竴涓榪涚▼涓鍙浠ュ寘鍚澶氫釜綰跨▼銆
涓涓綰跨▼鏄涓涓紼嬪簭鍐呴儴鐨勯『搴忔帶鍒舵祦銆
1. 榪涚▼錛氭瘡涓榪涚▼閮芥湁鐙絝嬬殑浠g爜鍜屾暟鎹絀洪棿錛堣繘紼嬩笂涓嬫枃錛 錛岃繘紼嬪垏鎹㈢殑寮閿澶с
2. 綰跨▼錛氳交閲忕殑榪涚▼錛屽悓涓綾葷嚎紼嬪叡浜浠g爜鍜屾暟鎹絀洪棿錛屾瘡涓綰跨▼鏈夌嫭絝嬬殑榪愯屾爤鍜岀▼搴忚℃暟鍣錛圥C錛夛紝綰跨▼鍒囨崲鐨勫紑閿灝忋
3. 澶氳繘紼嬶細鍦ㄦ搷浣滅郴緇熶腑錛岃兘鍚屾椂榪愯屽氫釜浠誨姟紼嬪簭銆
4. 澶氱嚎紼嬶細鍦ㄥ悓涓搴旂敤紼嬪簭涓錛屾湁澶氫釜欏哄簭嫻佸悓鏃舵墽琛屻
6錛1錛1 綰跨▼鐨勬傚康妯″瀷
Java鍐呭湪鏀鎸佸氱嚎紼嬶紝瀹冪殑鎵鏈夌被閮芥槸鍦ㄥ氱嚎紼嬩笅瀹氫箟鐨勶紝Java鍒╃敤澶氱嚎紼嬩嬌鏁翠釜緋葷粺鎴愪負寮傛ョ郴緇熴侸ava涓鐨勭嚎紼嬬敱涓夐儴鍒嗙粍鎴愶紝濡傚浘6.1鎵紺恆
1. 鉶氭嫙鐨凜PU錛屽皝瑁呭湪Java.lang.Thread綾諱腑銆
2. CPU鎵鎵ц岀殑浠g爜錛屼紶閫掔粰Thread綾匯
3. CPU鎵澶勭悊鐨勬暟鎹錛屼紶閫掔粰Thread綾匯
鍥6.1綰跨▼
6. 1. 2 綰跨▼浣(1)
Java鐨勭嚎紼嬫槸閫氳繃Java.lang.Thread綾繪潵瀹炵幇鐨勩傚綋鎴戜滑鐢熸垚涓涓猅hread綾葷殑瀵硅薄涔嬪悗,涓涓鏂扮殑綰跨▼灝變駭鐢熶簡銆
姝ょ嚎紼嬪疄渚嬭〃紺篔ava瑙i噴鍣ㄤ腑鐨勭湡姝g殑綰跨▼錛岄氳繃瀹冨彲浠ュ惎鍔ㄧ嚎紼嬨佺粓姝㈢嚎紼嬨佺嚎紼嬫寕璧風瓑錛屾瘡涓綰跨▼閮芥槸閫氳繃綾籘hread鍦↗ava鐨勮蔣浠跺寘Java.lang涓瀹氫箟錛屽畠鐨勬瀯閫犳柟娉曚負錛
public Thread 錛圱hreadGroup group錛孯unnable target錛孲tring name錛夛紱
鍏朵腑錛実roup 鎸囨槑璇ョ嚎紼嬫墍灞炵殑綰跨▼緇勶紱target瀹為檯鎵ц岀嚎紼嬩綋鐨勭洰鏍囧硅薄錛屽畠蹇呴』瀹炵幇鎺ュ彛Runnable錛 name涓虹嚎紼嬪悕銆侸ava涓鐨勬瘡涓綰跨▼閮芥湁鑷宸辯殑鍚嶇О錛孞ava鎻愪緵浜嗕笉鍚孴hread綾繪瀯閫犲櫒錛屽厑璁哥粰綰跨▼鎸囧畾鍚嶇О銆傚傛灉name涓簄ull鏃訛紝鍒橨ava鑷鍔ㄦ彁渚涘敮涓鐨勫悕縐般
褰撲笂榪版瀯閫犳柟娉曠殑鏌愪釜鍙傛暟涓簄ull鏃訛紝鎴戜滑鍙寰楀埌涓嬮潰鐨勫嚑涓鏋勯犳柟娉曪細
public Thread 錛堬級錛
public Thread 錛圧unnable target錛夛紱
public Thread 錛圧unnable target錛孲tring name錛夛紱
public Thread 錛圫tring name錛夛紱
public Thread 錛圱hreadGroup group錛孯unnable target錛夛紱
public Thread 錛圱hreadGroup group錛孲tring name錛夛紱
涓涓綾誨0鏄庡疄鐜癛unnable鎺ュ彛灝卞彲浠ュ厖褰撶嚎紼嬩綋錛屽湪鎺ュ彛Runnable涓鍙瀹氫箟浜嗕竴涓鏂規硶 run錛堬級錛
public void run錛堬級錛
浠諱綍瀹炵幇鎺ュ彛Runnable鐨勫硅薄閮藉彲浠ヤ綔涓轟竴涓綰跨▼鐨勭洰鏍囧硅薄錛岀被Thread鏈韜涔熷疄鐜頒簡鎺ュ彛Runnable錛屽洜姝ゆ垜浠鍙浠ラ氳繃涓ょ嶆柟娉曞疄鐜扮嚎紼嬩綋銆
錛堜竴錛夊畾涔変竴涓綰跨▼綾伙紝瀹冪戶鎵跨嚎紼嬬被Thread騫墮噸鍐欏叾涓鐨勬柟娉 run錛堬級錛岃繖鏃跺湪鍒濆嬪寲榪欎釜綾葷殑瀹炰緥鏃訛紝鐩鏍噒arget鍙涓簄ull錛岃〃紺虹敱榪欎釜瀹炰緥瀵規潵鎵ц岀嚎紼嬩綋銆傜敱浜嶫ava鍙鏀鎸佸崟閲嶇戶鎵匡紝鐢ㄨ繖縐嶆柟娉曞畾涔夌殑綾諱笉鑳藉啀緇ф壙鍏跺畠鐖剁被銆
錛堜簩錛夋彁渚涗竴涓瀹炵幇鎺ュ彛Runnable鐨勭被浣滀負涓涓綰跨▼鐨勭洰鏍囧硅薄錛屽湪鍒濆嬪寲涓涓猅hread綾繪垨鑰匱hread瀛愮被鐨勭嚎紼嬪硅薄鏃訛紝鎶婄洰鏍囧硅薄浼犻掔粰榪欎釜綰跨▼瀹炰緥錛岀敱璇ョ洰鏍囧硅薄鎻愪緵綰跨▼浣 run錛堬級銆傝繖鏃訛紝瀹炵幇鎺ュ彛Runnable鐨勭被浠嶇劧鍙浠ョ戶鎵垮叾瀹冪埗綾匯
姣忎釜綰跨▼閮芥槸閫氳繃鏌愪釜鐗瑰畾Thread瀵硅薄鐨勬柟娉時un( )鏉ュ畬鎴愬叾鎿嶄綔鐨勶紝鏂規硶run( )縐頒負綰跨▼浣撱傚浘6.2琛ㄧず浜咼ava綰跨▼鐨勪笉鍚岀姸鎬佷互鍙婄姸鎬佷箣闂磋漿鎹㈡墍璋冪敤鐨勬柟娉曘
鍥6.2 綰跨▼鐨勭姸鎬
1. 鍒涘緩鐘舵(new Thread)
鎵ц屼笅鍒楄鍙ユ椂錛岀嚎紼嬪氨澶勪簬鍒涘緩鐘舵侊細
Thread myThread = new MyThreadClass( );
褰撲竴涓綰跨▼澶勪簬鍒涘緩鐘舵佹椂錛屽畠浠呬粎鏄涓涓絀虹殑綰跨▼瀵硅薄錛岀郴緇熶笉涓哄畠鍒嗛厤璧勬簮銆
2. 鍙榪愯岀姸鎬( Runnable )
Thread myThread = new MyThreadClass( );
myThread.start( );
褰撲竴涓綰跨▼澶勪簬鍙榪愯岀姸鎬佹椂錛岀郴緇熶負榪欎釜綰跨▼鍒嗛厤浜嗗畠闇鐨勭郴緇熻祫婧愶紝瀹夋帓鍏惰繍琛屽苟璋冪敤綰跨▼榪愯屾柟娉曪紝榪欐牱灝變嬌寰楄ョ嚎紼嬪勪簬鍙榪愯( Runnable )鐘舵併傞渶瑕佹敞鎰忕殑鏄榪欎竴鐘舵佸苟涓嶆槸榪愯屼腑鐘舵侊紙Running )錛屽洜涓虹嚎紼嬩篃璁稿疄闄呬笂騫舵湭鐪熸h繍琛屻傜敱浜庡緢澶氳$畻鏈洪兘鏄鍗曞勭悊鍣ㄧ殑錛屾墍浠ヨ佸湪鍚屼竴鏃跺埢榪愯屾墍鏈夌殑澶勪簬鍙榪愯岀姸鎬佺殑綰跨▼鏄涓嶅彲鑳界殑錛孞ava鐨勮繍琛岀郴緇熷繀欏誨疄鐜拌皟搴︽潵淇濊瘉榪欎簺綰跨▼鍏變韓澶勭悊鍣ㄣ
3. 涓嶅彲榪愯岀姸鎬侊紙Not Runnable錛
榪涘叆涓嶅彲榪愯岀姸鎬佺殑鍘熷洜鏈夊備笅鍑犳潯錛
1) 璋冪敤浜唖leep錛堬級鏂規硶;
2) 璋冪敤浜唖uspend錛堬級鏂規硶;
3) 涓虹瓑鍊欎竴涓鏉′歡鍙橀噺錛岀嚎紼嬭皟鐢╳ait錛堬級鏂規硶;
4) 杈撳叆杈撳嚭嫻佷腑鍙戠敓綰跨▼闃誨;
涓嶅彲榪愯岀姸鎬佷篃縐頒負闃誨炵姸鎬侊紙Blocked錛夈傚洜涓烘煇縐嶅師鍥狅紙杈撳叆/杈撳嚭銆佺瓑寰呮秷鎮鎴栧叾瀹冮樆濉炴儏鍐碉級錛岀郴緇熶笉鑳芥墽琛岀嚎紼嬬殑鐘舵併傝繖鏃跺嵆浣垮勭悊鍣ㄧ┖闂詫紝涔熶笉鑳芥墽琛岃ョ嚎紼嬨
4. 姝諱骸鐘舵侊紙Dead錛
綰跨▼鐨勭粓姝涓鑸鍙閫氳繃涓ょ嶆柟娉曞疄鐜幫細鑷鐒舵挙娑堬紙綰跨▼鎵ц屽畬錛夋垨鏄琚鍋滄錛堣皟鐢╯top()鏂規硶錛夈傜洰鍓嶄笉鎺ㄨ崘閫氳繃璋冪敤stop()鏉ョ粓姝㈢嚎紼嬬殑鎵ц岋紝鑰屾槸璁╃嚎紼嬫墽琛屽畬銆
http://www.bc-cn.net/Article/kfyy/java/jc/200410/83.html
『陸』 java線程for循環沒有循環完成就停止了,這是為什麼
多線程需要基礎學好點。在來開發,否則總有莫名其妙的事情冒出來。而自己無法解釋。
你這個問題很簡單。
你要main主線程1秒後輸出list集合數據。在你代碼中這寫法本身是錯誤的,因為你有2個子線程,有鎖,安全地往list中加2千個數據,卻每次要等待1毫秒,估算2千數據你程序的加完需要2秒多時間,在1秒後,子線程還沒有結束,大概1千個數據還沒加完呢,你主線程就輸出了當前數據。肯定結果不對。哪來的2千個數據呢。你說循環沒完成就停止了,說法完全錯誤。。。
你要main主線程輸出list集合數據。正確操作應該是:
Thread t1 = ...;
t1.start();
t2也是如此。
最後main線程下面,輸出list數據前加2行代碼
t1.join();
t2.join();
然後在列印list。
join方法意思很簡單。就是等待線程結束後,我再繼續。main線程等待了2個子線程都結束後,即保證數據全部進list後,列印結果。