JWorld@TW the best professional Java site in Taiwan
      註冊 | 登入 | 全文檢索 | 排行榜  

» JWorld@TW » Software Design  

按列印兼容模式列印這個話題 列印話題    把這個話題寄給朋友 寄給朋友    訂閱主題
reply to postflat modego to previous topicgo to next topic
本主題所含的標籤
無標籤
作者 Thread-Specific Storage 模式 [精華]
caterpillar

良葛格

版主

發文: 2613
積分: 70
於 2004-06-09 22:21 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
無論如何,要編寫一個多執行緒安全(thread-safe)的程式總是困難的,為了使用的共用資源,您必須小心的對共用資源進行同步,同步帶來一定的效能延遲,而另一方面,在處理同步的時候,又要注意物件的鎖定與釋放,避免產生死結,種種因素都使得編寫多執行緒程式變得困難。

Thread-Specific Storage 模式嘗試從另一個角度來解釋多執行緒共用資源的問題,其思考點很簡單,即然共用資源這麼困難,那麼就乾脆不要共用,何不為每個執行緒創造一個資源的複本,將每一個執行緒存取資料的行為加以隔離,其實現的方法,就是給予每一個執行緒一個特定空間來保管該執行緒所獨享的資源,也因此而稱之為Thread-Specific Storage模式。

在Java中,我們可以使用java.lang.ThreadLocal來實現這個模式,這個類別是從1.2之後開始提供,不過我們先來看看,如何自行實現一個簡單的ThreadLocal類別:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class ThreadLocal {
    private Map storage = Collections.synchronizedMap(new HashMap());
 
    public Object get() {
        Thread current = Thread.currentThread();
        Object o = storage.get(current);
 
        if(o == null && !stroage.containsKey(current)) {
            o = initialValue();
            storage.put(current, o);
        }
 
        return o;
    }
 
    public void set(Object o) {
        storage.put(Thread.currentThread(), o);
    }
 
    public Object initialValue() {
        return null;
    }
}


可以看到,我們使用執行緒本身作為key值,並將所獲得的資源放在Map物件中,如果第一次使用get(),我們也配置一個空間給執行緒,而initialValue()可以用來設定什麼樣的初值要先儲存在這個空間中,在這邊先簡單的設定為null。

現在假設有一個原先在單執行緒環境下的資源SomeResource,現在考慮要該其在多執行緒環境下使用,我們不想考慮複雜的執行緒共用互斥問題,此時我們可以使用ThreadLocal類別來使用SomeResource,例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Resource {
    private static final ThreadLocal threadLocal = new ThreadLocal();
 
    public static SomeResource getResource() {
        SomeResource resource = (SomeResource) threadLocal.get();
 
        if(resource == null) {
            resource = new SomeResource();
            threadLocal.set(resource);
        }
 
        return resource;
    }
}


我們上面所實作的ThreadLocal類別只是一個簡單的示範,您可以使用java.lang.ThreadLocal來實現Thread-Specific Storage模式,以獲得更好的效能,在這邊我們簡單的示範一個Log程式,它可以記錄每個執行緒的活動,所使用的是java.util.logging中的類別:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import java.io.*;
import java.util.logging.*;
                                                                                                
public class SimpleThreadLogger {
    private static final ThreadLocal threadLocal = new ThreadLocal();
                                                                                                
    public static void log(String msg) {
        getThreadLogger().log(Level.INFO, msg);
    }
                                                                                                
    private static Logger getThreadLogger() {
        Logger logger = (Logger) threadLocal.get();
                                                                                                
        if(logger == null) {
            try {
                logger = Logger.getLogger(Thread.currentThread().getName());
                // Logger 預設是在主控台輸出
                // 我們加入一個檔案輸出的Handler,它會輸出XML的記錄文件
                logger.addHandler(
                    new FileHandler(Thread.currentThread().getName() + ".log"));
            }
            catch(IOException e) {}
                                                                                                
            threadLocal.set(logger);
        }
 
        return logger;
    }
}


我們可以使用下面這個程式來測試:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class LoggerTest {
    public static void main(String[] args) {
        new TestThread("thread1").start();
        new TestThread("thread2").start();
        new TestThread("thread3").start();
    }
}
                                                                                                
class TestThread extends Thread {
    public TestThread(String name) {
        super(name);
    }
                                                                                                
    public void run() {
        for(int i = 0; i < 10; i++) {
            SimpleThreadLogger.log(getName() + ": message " + i);
            try {
                Thread.sleep(1000);
            }
            catch(Exception e) {
                SimpleThreadLogger.log(e.toString());
            }
        }
    }
}


執行LoggerTest,我們可以在主控台上看到輸出,並可以在同一目錄下找到三個log檔,分別記錄了三個執行緒的活動,透過ThreadLocal,我們不用撰寫複雜的執行緒共用互斥邏輯。

Thread-Specific Storage模式的意義之一,就是「有時不共用是好的」,如果共用會產生危險,那就不要共用,當然,這種方式所犧牲掉的就是空間,我們必須為每一個執行緒保留它們獨立的空間,這是一種以空間換取時間與安全性的方法。


reply to postreply to post
良葛格學習筆記
話題樹型展開
人氣 標題 作者 字數 發文時間
8156 [精華] Thread-Specific Storage 模式 caterpillar 4186 2004-06-09 22:21
5573 Re:Thread-Specific Storage 模式 ispot 141 2004-06-14 10:59
5447 Re:Thread-Specific Storage 模式 tempo 710 2004-06-14 12:38
5460 Re:Thread-Specific Storage 模式 alien 290 2004-06-14 13:27
5470 Re:Thread-Specific Storage 模式 tempo 526 2004-06-14 20:37
5475 Re:Thread-Specific Storage 模式 alien 581 2004-06-15 09:10
6297 Re:Thread-Specific Storage 模式 tempo 19 2004-06-15 12:29
» JWorld@TW »  Software Design

reply to postflat modego to previous topicgo to next topic
  已讀文章
  新的文章
  被刪除的文章
Jump to the top of page

JWorld@TW 本站商標資訊

Powered by Powerful JuteForum® Version Jute 1.5.8