Java線程個數簡單控制

系統在運行時,有時候我們要控制它同時允許多少個線程運行,如果太多可能引起內存溢出之類的異常,所以在線程比較多的情況下我們可以控制它的最大線程數,這樣系統可以在一種比較穩定的狀態下運行。下面是一個簡單實現,可以少加修改用在系統中去。

 

Java代碼 複製代碼 收藏代碼
  1. package thread;   
  2.   
  3.   
  4. public class CreateThread {   
  5.   
  6.     public static void main(String[] args) throws InterruptedException {   
  7.         //比如我們現要創建30個子線程,但允許最大線程數爲10   
  8.         for (int i = 0; i < 30; i++) {   
  9.             // 獲取鎖資源   
  10.             synchronized (SubThread.class) {   
  11.                 int tCount = SubThread.getThreadCounts();   
  12.   
  13.                 // 如果入庫線程達到了最大允許的線程數   
  14.                 while (tCount >= 10) {   
  15.                     System.out.println("系統當前線程數爲:" + tCount   
  16.                             + ",已達到最大線程數 10,請等待其他線程執行完畢並釋放系統資源");   
  17.                     // 釋放鎖,等待“線程數”資源,等待其他入庫線程執行完畢   
  18.                     SubThread.class.wait();   
  19.   
  20.                     /*  
  21.                      * 帶條件的wait()(即放在條件語句執行的wait()方法),一定要放在while  
  22.                      * 條件裏執行,因爲被喚醒之後該線程有可能不會馬上執行,只是把當前線程從等  
  23.                      * 待池中放入對象鎖池隊列中,直到獲取到鎖後纔開始運行。所以在同步塊裏wait方  
  24.                      * 法前後的代碼塊不是原子性的,會分開執行,但sleep()不同,睡時不會釋放鎖。  
  25.                      * 所以等到執行時,可能條件已被其他的線程給改變了(像這裏的最大線程數),此  
  26.                      * 時就需要再此判斷該條件,否則條件可能不成立了  
  27.                      */  
  28.                     tCount = SubThread.getThreadCounts();   
  29.                 }   
  30.                 // 重新啓動一個子線程   
  31.                 Thread td = new SubThread();   
  32.                 td.start();   
  33.                 System.out.println("已創建新的子線程: " + td.getName());   
  34.             }   
  35.         }   
  36.   
  37.     }   
  38. }  
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());
			}
		}

	}
}
 
Java代碼 複製代碼 收藏代碼
  1. package thread;   
  2.   
  3. public class SubThread extends Thread {   
  4.   
  5.     // 線程計數器   
  6.     static private int threadCounts;   
  7.   
  8.     // 線程名稱池   
  9.     static private String threadNames[];   
  10.     static {   
  11.         // 假設這裏允許系統同時運行最大線程數爲10個   
  12.         int maxThreadCounts = 10;   
  13.         threadNames = new String[maxThreadCounts];   
  14.         // 初始化線程名稱池   
  15.         for (int i = 1; i <= maxThreadCounts; i++) {   
  16.             threadNames[i - 1] = "子線程_" + i;   
  17.         }   
  18.     }   
  19.   
  20.     public SubThread() {   
  21.         // 臨界資源鎖定   
  22.         synchronized (SubThread.class) {   
  23.             // 線程總數加1   
  24.             threadCounts++;   
  25.   
  26.             // 從線程名稱池中取出一個未使用的線程名   
  27.             for (int i = 0; i < threadNames.length; i++) {   
  28.                 if (threadNames[i] != null) {   
  29.                     String temp = threadNames[i];   
  30.                     // 名被佔用後清空   
  31.                     threadNames[i] = null;   
  32.                     // 初始化線程名稱   
  33.                     this.setName(temp);   
  34.                     break;   
  35.                 }   
  36.             }   
  37.         }   
  38.     }   
  39.   
  40.     public void run() {   
  41.         System.out.println("-->>" + this.getName() + "開始運行");   
  42.         try {   
  43.             //模擬程序耗時   
  44.             Thread.sleep(1000);   
  45.             // ...   
  46.         } catch (Exception e) {   
  47.             System.out.println(e);   
  48.         } finally {   
  49.             synchronized (SubThread.class) {   
  50.   
  51.                 // 線程運行完畢後減1   
  52.                 threadCounts--;   
  53.   
  54.                 // 釋放線程名稱   
  55.                 String[] threadName = this.getName().split("_");   
  56.   
  57.                 // 線程名使用完後放入名稱池   
  58.                 threadNames[Integer.parseInt(threadName[1]) - 1] = this.getName();   
  59.   
  60.                 /*  
  61.                  * 通知其他被阻塞的線程,但如果其他線程要執行,則該同步塊一定要運行結束(即直  
  62.                  * 到釋放佔的鎖),其他線程纔有機會執行,所以這裏的只是喚醒在此對象監視器上等待  
  63.                  * 的所有線程,讓他們從等待池中進入對象鎖池隊列中,而這些線程重新運行時它們一定  
  64.                  * 要先要得該鎖後纔可能執行,這裏的notifyAll是不會釋放鎖的,試着把下面的睡眠語  
  65.                  * 句註釋去掉,即使你已調用了notify方法,發現CreateThread中的同步塊還是好  
  66.                  * 像一直處於對象等待狀態,其實調用notify方法後,CreateThread線程進入了對象鎖  
  67.                  * 池隊列中了,只要它一獲取到鎖,CreateThread所在線程就會真真的被喚醒並運行。  
  68.                  */  
  69.                 SubThread.class.notifyAll();   
  70. //              try {   
  71. //                  Thread.sleep(10000);   
  72. //              } catch (InterruptedException e) {   
  73. //                  e.printStackTrace();   
  74. //              }   
  75.                 System.out.println("----" + this.getName() + " 所佔用資源釋放完畢,當前系統正在運行的子線程數:"  
  76.                         + threadCounts);   
  77.             }   
  78.             System.out.println("<<--" + this.getName() + "運行結束");   
  79.         }   
  80.     }   
  81.   
  82.     static public int getThreadCounts() {   
  83.         synchronized (SubThread.class) {   
  84.             return threadCounts;   
  85.         }   
  86.     }   
  87. }  
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運行結束

發佈了23 篇原創文章 · 獲贊 0 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章