系統在運行時,有時候我們要控制它同時允許多少個線程運行,如果太多可能引起內存溢出之類的異常,所以在線程比較多的情況下我們可以控制它的最大線程數,這樣系統可以在一種比較穩定的狀態下運行。下面是一個簡單實現,可以少加修改用在系統中去。
- package thread;
- public class CreateThread {
- public static void main(String[] args) throws InterruptedException {
- //比如我們現要創建30個子線程,但允許最大線程數爲10
- for (int i = 0; i < 30; i++) {
- // 獲取鎖資源
- synchronized (SubThread.class) {
- int tCount = SubThread.getThreadCounts();
- // 如果入庫線程達到了最大允許的線程數
- while (tCount >= 10) {
- System.out.println("系統當前線程數爲:" + tCount
- + ",已達到最大線程數 10,請等待其他線程執行完畢並釋放系統資源");
- // 釋放鎖,等待“線程數”資源,等待其他入庫線程執行完畢
- SubThread.class.wait();
- /*
- * 帶條件的wait()(即放在條件語句執行的wait()方法),一定要放在while
- * 條件裏執行,因爲被喚醒之後該線程有可能不會馬上執行,只是把當前線程從等
- * 待池中放入對象鎖池隊列中,直到獲取到鎖後纔開始運行。所以在同步塊裏wait方
- * 法前後的代碼塊不是原子性的,會分開執行,但sleep()不同,睡時不會釋放鎖。
- * 所以等到執行時,可能條件已被其他的線程給改變了(像這裏的最大線程數),此
- * 時就需要再此判斷該條件,否則條件可能不成立了
- */
- tCount = SubThread.getThreadCounts();
- }
- // 重新啓動一個子線程
- Thread td = new SubThread();
- td.start();
- System.out.println("已創建新的子線程: " + td.getName());
- }
- }
- }
- }
package thread;
public class CreateThread {
public static void main(String[] args) throws InterruptedException {
//比如我們現要創建30個子線程,但允許最大線程數爲10
for (int i = 0; i < 30; i++) {
// 獲取鎖資源
synchronized (SubThread.class) {
int tCount = SubThread.getThreadCounts();
// 如果入庫線程達到了最大允許的線程數
while (tCount >= 10) {
System.out.println("系統當前線程數爲:" + tCount
+ ",已達到最大線程數 10,請等待其他線程執行完畢並釋放系統資源");
// 釋放鎖,等待“線程數”資源,等待其他入庫線程執行完畢
SubThread.class.wait();
/*
* 帶條件的wait()(即放在條件語句執行的wait()方法),一定要放在while
* 條件裏執行,因爲被喚醒之後該線程有可能不會馬上執行,只是把當前線程從等
* 待池中放入對象鎖池隊列中,直到獲取到鎖後纔開始運行。所以在同步塊裏wait方
* 法前後的代碼塊不是原子性的,會分開執行,但sleep()不同,睡時不會釋放鎖。
* 所以等到執行時,可能條件已被其他的線程給改變了(像這裏的最大線程數),此
* 時就需要再此判斷該條件,否則條件可能不成立了
*/
tCount = SubThread.getThreadCounts();
}
// 重新啓動一個子線程
Thread td = new SubThread();
td.start();
System.out.println("已創建新的子線程: " + td.getName());
}
}
}
}
- package thread;
- public class SubThread extends Thread {
- // 線程計數器
- static private int threadCounts;
- // 線程名稱池
- static private String threadNames[];
- static {
- // 假設這裏允許系統同時運行最大線程數爲10個
- int maxThreadCounts = 10;
- threadNames = new String[maxThreadCounts];
- // 初始化線程名稱池
- for (int i = 1; i <= maxThreadCounts; i++) {
- threadNames[i - 1] = "子線程_" + i;
- }
- }
- public SubThread() {
- // 臨界資源鎖定
- synchronized (SubThread.class) {
- // 線程總數加1
- threadCounts++;
- // 從線程名稱池中取出一個未使用的線程名
- for (int i = 0; i < threadNames.length; i++) {
- if (threadNames[i] != null) {
- String temp = threadNames[i];
- // 名被佔用後清空
- threadNames[i] = null;
- // 初始化線程名稱
- this.setName(temp);
- break;
- }
- }
- }
- }
- public void run() {
- System.out.println("-->>" + this.getName() + "開始運行");
- try {
- //模擬程序耗時
- Thread.sleep(1000);
- // ...
- } catch (Exception e) {
- System.out.println(e);
- } finally {
- synchronized (SubThread.class) {
- // 線程運行完畢後減1
- threadCounts--;
- // 釋放線程名稱
- String[] threadName = this.getName().split("_");
- // 線程名使用完後放入名稱池
- threadNames[Integer.parseInt(threadName[1]) - 1] = this.getName();
- /*
- * 通知其他被阻塞的線程,但如果其他線程要執行,則該同步塊一定要運行結束(即直
- * 到釋放佔的鎖),其他線程纔有機會執行,所以這裏的只是喚醒在此對象監視器上等待
- * 的所有線程,讓他們從等待池中進入對象鎖池隊列中,而這些線程重新運行時它們一定
- * 要先要得該鎖後纔可能執行,這裏的notifyAll是不會釋放鎖的,試着把下面的睡眠語
- * 句註釋去掉,即使你已調用了notify方法,發現CreateThread中的同步塊還是好
- * 像一直處於對象等待狀態,其實調用notify方法後,CreateThread線程進入了對象鎖
- * 池隊列中了,只要它一獲取到鎖,CreateThread所在線程就會真真的被喚醒並運行。
- */
- SubThread.class.notifyAll();
- // try {
- // Thread.sleep(10000);
- // } catch (InterruptedException e) {
- // e.printStackTrace();
- // }
- System.out.println("----" + this.getName() + " 所佔用資源釋放完畢,當前系統正在運行的子線程數:"
- + threadCounts);
- }
- System.out.println("<<--" + this.getName() + "運行結束");
- }
- }
- static public int getThreadCounts() {
- synchronized (SubThread.class) {
- return threadCounts;
- }
- }
- }
package thread;
public class SubThread extends Thread {
// 線程計數器
static private int threadCounts;
// 線程名稱池
static private String threadNames[];
static {
// 假設這裏允許系統同時運行最大線程數爲10個
int maxThreadCounts = 10;
threadNames = new String[maxThreadCounts];
// 初始化線程名稱池
for (int i = 1; i <= maxThreadCounts; i++) {
threadNames[i - 1] = "子線程_" + i;
}
}
public SubThread() {
// 臨界資源鎖定
synchronized (SubThread.class) {
// 線程總數加1
threadCounts++;
// 從線程名稱池中取出一個未使用的線程名
for (int i = 0; i < threadNames.length; i++) {
if (threadNames[i] != null) {
String temp = threadNames[i];
// 名被佔用後清空
threadNames[i] = null;
// 初始化線程名稱
this.setName(temp);
break;
}
}
}
}
public void run() {
System.out.println("-->>" + this.getName() + "開始運行");
try {
//模擬程序耗時
Thread.sleep(1000);
// ...
} catch (Exception e) {
System.out.println(e);
} finally {
synchronized (SubThread.class) {
// 線程運行完畢後減1
threadCounts--;
// 釋放線程名稱
String[] threadName = this.getName().split("_");
// 線程名使用完後放入名稱池
threadNames[Integer.parseInt(threadName[1]) - 1] = this.getName();
/*
* 通知其他被阻塞的線程,但如果其他線程要執行,則該同步塊一定要運行結束(即直
* 到釋放佔的鎖),其他線程纔有機會執行,所以這裏的只是喚醒在此對象監視器上等待
* 的所有線程,讓他們從等待池中進入對象鎖池隊列中,而這些線程重新運行時它們一定
* 要先要得該鎖後纔可能執行,這裏的notifyAll是不會釋放鎖的,試着把下面的睡眠語
* 句註釋去掉,即使你已調用了notify方法,發現CreateThread中的同步塊還是好
* 像一直處於對象等待狀態,其實調用notify方法後,CreateThread線程進入了對象鎖
* 池隊列中了,只要它一獲取到鎖,CreateThread所在線程就會真真的被喚醒並運行。
*/
SubThread.class.notifyAll();
// try {
// Thread.sleep(10000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
System.out.println("----" + this.getName() + " 所佔用資源釋放完畢,當前系統正在運行的子線程數:"
+ threadCounts);
}
System.out.println("<<--" + this.getName() + "運行結束");
}
}
static public int getThreadCounts() {
synchronized (SubThread.class) {
return threadCounts;
}
}
}
某次運行結果:
已創建新的子線程: 子線程_1
已創建新的子線程: 子線程_2
已創建新的子線程: 子線程_3
-->>子線程_2開始運行
已創建新的子線程: 子線程_4
-->>子線程_4開始運行
已創建新的子線程: 子線程_5
已創建新的子線程: 子線程_6
-->>子線程_6開始運行
已創建新的子線程: 子線程_7
已創建新的子線程: 子線程_8
已創建新的子線程: 子線程_9
已創建新的子線程: 子線程_10
系統當前線程數爲:10,已達到最大線程數 10,請等待其他線程執行完畢並釋放系統資源
-->>子線程_1開始運行
-->>子線程_8開始運行
-->>子線程_10開始運行
-->>子線程_3開始運行
-->>子線程_5開始運行
-->>子線程_7開始運行
-->>子線程_9開始運行
----子線程_2 所佔用資源釋放完畢,當前系統正在運行的子線程數:9
已創建新的子線程: 子線程_2
系統當前線程數爲:10,已達到最大線程數 10,請等待其他線程執行完畢並釋放系統資源
<<--子線程_2運行結束
-->>子線程_2開始運行
----子線程_4 所佔用資源釋放完畢,當前系統正在運行的子線程數:9
<<--子線程_4運行結束
已創建新的子線程: 子線程_4
系統當前線程數爲:10,已達到最大線程數 10,請等待其他線程執行完畢並釋放系統資源
-->>子線程_4開始運行
----子線程_6 所佔用資源釋放完畢,當前系統正在運行的子線程數:9
<<--子線程_6運行結束
----子線程_10 所佔用資源釋放完畢,當前系統正在運行的子線程數:8
<<--子線程_10運行結束
----子線程_8 所佔用資源釋放完畢,當前系統正在運行的子線程數:7
<<--子線程_8運行結束
已創建新的子線程: 子線程_6
已創建新的子線程: 子線程_8
已創建新的子線程: 子線程_10
系統當前線程數爲:10,已達到最大線程數 10,請等待其他線程執行完畢並釋放系統資源
----子線程_1 所佔用資源釋放完畢,當前系統正在運行的子線程數:9
<<--子線程_1運行結束
-->>子線程_6開始運行
-->>子線程_10開始運行
已創建新的子線程: 子線程_1
----子線程_7 所佔用資源釋放完畢,當前系統正在運行的子線程數:9
<<--子線程_7運行結束
----子線程_9 所佔用資源釋放完畢,當前系統正在運行的子線程數:8
<<--子線程_9運行結束
-->>子線程_8開始運行
-->>子線程_1開始運行
----子線程_5 所佔用資源釋放完畢,當前系統正在運行的子線程數:7
<<--子線程_5運行結束
----子線程_3 所佔用資源釋放完畢,當前系統正在運行的子線程數:6
<<--子線程_3運行結束
已創建新的子線程: 子線程_3
已創建新的子線程: 子線程_5
-->>子線程_5開始運行
已創建新的子線程: 子線程_7
已創建新的子線程: 子線程_9
系統當前線程數爲:10,已達到最大線程數 10,請等待其他線程執行完畢並釋放系統資源
-->>子線程_9開始運行
-->>子線程_3開始運行
-->>子線程_7開始運行
----子線程_4 所佔用資源釋放完畢,當前系統正在運行的子線程數:9
<<--子線程_4運行結束
----子線程_8 所佔用資源釋放完畢,當前系統正在運行的子線程數:8
<<--子線程_8運行結束
----子線程_1 所佔用資源釋放完畢,當前系統正在運行的子線程數:7
<<--子線程_1運行結束
已創建新的子線程: 子線程_1
已創建新的子線程: 子線程_4
-->>子線程_4開始運行
已創建新的子線程: 子線程_8
-->>子線程_1開始運行
-->>子線程_8開始運行
----子線程_5 所佔用資源釋放完畢,當前系統正在運行的子線程數:9
<<--子線程_5運行結束
已創建新的子線程: 子線程_5
----子線程_2 所佔用資源釋放完畢,當前系統正在運行的子線程數:9
<<--子線程_2運行結束
----子線程_6 所佔用資源釋放完畢,當前系統正在運行的子線程數:8
<<--子線程_6運行結束
-->>子線程_5開始運行
----子線程_10 所佔用資源釋放完畢,當前系統正在運行的子線程數:7
<<--子線程_10運行結束
----子線程_9 所佔用資源釋放完畢,當前系統正在運行的子線程數:6
<<--子線程_9運行結束
已創建新的子線程: 子線程_2
已創建新的子線程: 子線程_6
已創建新的子線程: 子線程_9
已創建新的子線程: 子線程_10
系統當前線程數爲:10,已達到最大線程數 10,請等待其他線程執行完畢並釋放系統資源
-->>子線程_6開始運行
-->>子線程_10開始運行
----子線程_3 所佔用資源釋放完畢,當前系統正在運行的子線程數:9
已創建新的子線程: 子線程_3
系統當前線程數爲:10,已達到最大線程數 10,請等待其他線程執行完畢並釋放系統資源
<<--子線程_3運行結束
----子線程_7 所佔用資源釋放完畢,當前系統正在運行的子線程數:9
已創建新的子線程: 子線程_7
<<--子線程_7運行結束
-->>子線程_2開始運行
-->>子線程_9開始運行
-->>子線程_7開始運行
-->>子線程_3開始運行
----子線程_4 所佔用資源釋放完畢,當前系統正在運行的子線程數:9
<<--子線程_4運行結束
----子線程_1 所佔用資源釋放完畢,當前系統正在運行的子線程數:8
<<--子線程_1運行結束
----子線程_8 所佔用資源釋放完畢,當前系統正在運行的子線程數:7
<<--子線程_8運行結束
----子線程_5 所佔用資源釋放完畢,當前系統正在運行的子線程數:6
<<--子線程_5運行結束
----子線程_6 所佔用資源釋放完畢,當前系統正在運行的子線程數:5
<<--子線程_6運行結束
----子線程_10 所佔用資源釋放完畢,當前系統正在運行的子線程數:4
<<--子線程_10運行結束
----子線程_2 所佔用資源釋放完畢,當前系統正在運行的子線程數:3
<<--子線程_2運行結束
----子線程_7 所佔用資源釋放完畢,當前系統正在運行的子線程數:2
<<--子線程_7運行結束
----子線程_9 所佔用資源釋放完畢,當前系統正在運行的子線程數:1
<<--子線程_9運行結束
----子線程_3 所佔用資源釋放完畢,當前系統正在運行的子線程數:0
<<--子線程_3運行結束