java多線程編程

在多線程編程下,對處理併發時,可能產生重複工作的線程,

首先,從基礎的說起

第一步如何創建一個線程、運行一個線程

Tread thread = new Thread();
thread.start();
第二步,在線程裏實現功能

這裏大部分部分內容參考了http://ifeve.com/creating-and-starting-java-threads/

由於,線程啓動之後會自動運行run()函數裏的代碼,所以需要實現功能有兩種方式:

一種是創建Thread子類的一個實例並重寫run方法

public class MyThread extends Thread {
   public void run(){
     System.out.println("MyThread running");
   }
}

可以用如下方式創建並運行上述Thread子類

MyThread myThread = new MyThread();
myTread.start();
創建匿名類的方式

Thread thread = new Thread(){
   public void run(){
     System.out.println("Thread Running");
   }
};
thread.start();
第二種是創建類的時候實現Runnable接口:

public class MyRunnable implements Runnable {
   public void run(){
    System.out.println("MyRunnable running");
   }
}
爲了使線程能夠執行run()方法,需要在Thread類的構造函數中傳入 MyRunnable的實例對象。示例如下:

Thread thread = new Thread(new MyRunnable());
thread.start();
匿名類實現:

Runnable myRunnable = new Runnable(){
   public void run(){
     System.out.println("Runnable running");
   }
}
Thread thread = new Thread(myRunnable);
thread.start();
具體這兩種的比較,網上有很多資料可以查,但有一點:因爲線程池可以有效的管理實現了Runnable接口的線程,如果線程池滿了,新的線程就會排隊等候執行,直到線程池空閒出來爲止。而如果線程是通過實現Thread子類實現的,這將會複雜一些,有時需要兩種方式都用。

常見錯誤:調用run()方法而非start()方法

創建並運行一個線程所犯的常見錯誤是調用線程的run()方法而非start()方法,如下所示:

Thread newThread = new Thread(MyRunnable());
newThread.run();  //should be start();

事實上,run()方法並非是由剛創建的新線程所執行的,而是被創建新線程的當前線程所執行了。也就是被執行上面兩行代碼的線程所執行的。想要讓創建的新線程執行run()方法,必須調用新線程的start方法。

第三步,向線程中傳遞參數

一般來說,線程中處理的事務多數需要外界參數,這裏有三種方法,具體參考

http://www.jb51.net/article/31981.htm

第四步,在多線程環境下,找到指定命名的當前運行的線程

第一點是給線程命名
當創建一個線程的時候,可以給線程起一個名字。它有助於我們區分不同的線程。例如:如果有多個線程寫入System.out,我們就能夠通過線程名容易的找出是哪個線程正在輸出。例子如下:

MyRunnable runnable = new MyRunnable();
Thread thread = new Thread(runnable, "New Thread");
thread.start();
System.out.println(thread.getName());
需要注意的是,因爲MyRunnable並非Thread的子類,所以MyRunnable類並沒有getName()方法。可以通過以下方式得到當前線程的引用:

Thread.currentThread();
因此,通過如下代碼可以得到當前線程的名字:
String threadName = Thread.currentThread().getName();
線程代碼舉例:
這裏是一個小小的例子。首先輸出執行main()方法線程名字。這個線程JVM分配的。然後開啓10個線程,命名爲1~10。每個線程輸出自己的名字後就退出。

public class ThreadExample {
  public static void main(String[] args){
     System.out.println(Thread.currentThread().getName());
      for(int i=0; i<10; i++){
         new Thread("" + i){
            public void run(){
             System.out.println("Thread: " + getName() + "running");
            }
         }.start();
      }
  }
}
需要注意的是,儘管啓動線程的順序是有序的,但是執行的順序並非是有序的。也就是說,1號線程並不一定是第一個將自己名字輸出到控制檯的線程。這是因爲線程是並行執行而非順序的。Jvm和操作系統一起決定了線程的執行順序,他和線程的啓動順序並非一定是一致的。

第二點是找到對應名稱的線程

在多線程編程中,處理併發情況下,很容易出現某一個線程的內容重複使用,如果線程使用率較高,或者某個線程具有延遲等功能的話,多次創建新的線程不利於線程管理,也容易造成阻塞,所以,在這些線程的過程中需要判斷,當前運行的線程中是否有對應名字的線程

下面代碼用於取得所有的正在運行線程的名字:

ThreadGroup group = Thread.currentThread().getThreadGroup();
ThreadGroup topGroup = group;
// 遍歷線程組樹,獲取根線程組
while (group != null) {
	topGroup = group;
	group = group.getParent();
}
// 激活的線程數加倍
int estimatedSize = topGroup.activeCount() * 2;
Thread[] slackList = new Thread[estimatedSize];
// 獲取根線程組的所有線程
int actualSize = topGroup.enumerate(slackList);
// copy into a list that is the exact size
Thread[] list = new Thread[actualSize];
System.arraycopy(slackList, 0, list, 0, actualSize);
System.out.println("Thread list size == " + list.length);
for (Thread thread : list) {
	System.out.println(thread.getName());    //這裏取得名字後可以進行邏輯操作
}

這裏其實有個問題,因爲拿到的是所有線程,包括父線程,所以當同一時間運行程序很多的時候可能會拿到大量無用的線程,

在工程中可以建立一個靜態列表,在創建某個線程的時候,把命名放在這個列表裏面,然後在搜素的時候可以先查列表,如果只是知道某個線程在不在啓動,則可以用這個簡便算法

最後再次感謝

http://ifeve.com/creating-and-starting-java-threads/

http://www.jb51.net/article/31981.htm

http://trinityblood.iteye.com/blog/1618181

三位作者的大力支持



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章