多线程模式(八)Thread-Specific Storage
2009-04-09 19:55
176 查看
Thread-Specific Storage模式嘗試從另一個角度來解釋多執行緒共用資源的問題,其思考點很簡單,即然共用資源這麼困難,那麼就乾脆不要共用,何不為每個執行緒創造一
個資源的複本,將每一個執行緒存取資料的行為加以隔離,其實現的方法,就是給予每一個執行緒一個特定空間來保管該執行緒所獨享的資源,也因此而稱之為 Thread- Specific Storage模式。
在Java中可以使用java.lang.ThreadLocal來實現這個模式,這個類別是從1.2之後開始提供,不過先來看看,如何自行實 現一個簡單的ThreadLocal類別:
ThreadLocal.java
import java.util.*;
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 &&
!storage.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,例如:
Resource.java
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中的類別:
SimpleThreadLogger.java
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;
}
}
可以使用下面這個程式來測試:
LoggerTest.java
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模式的意義之一,就是「有時不共用是好的」,如果共用會產生危險,那就不要共用,當然,這種方式所犧牲掉的就是空間,您必須為每一個執行
緒保留它們獨立的空間,這是一種以空間換取時間與安全性的方法。
個資源的複本,將每一個執行緒存取資料的行為加以隔離,其實現的方法,就是給予每一個執行緒一個特定空間來保管該執行緒所獨享的資源,也因此而稱之為 Thread- Specific Storage模式。
在Java中可以使用java.lang.ThreadLocal來實現這個模式,這個類別是從1.2之後開始提供,不過先來看看,如何自行實 現一個簡單的ThreadLocal類別:
ThreadLocal.java
import java.util.*;
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 &&
!storage.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,例如:
Resource.java
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中的類別:
SimpleThreadLogger.java
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;
}
}
可以使用下面這個程式來測試:
LoggerTest.java
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模式的意義之一,就是「有時不共用是好的」,如果共用會產生危險,那就不要共用,當然,這種方式所犧牲掉的就是空間,您必須為每一個執行
緒保留它們獨立的空間,這是一種以空間換取時間與安全性的方法。
相关文章推荐
- 多线程模式(四)-Thread Per Message
- java多线程之Thread-Specific Storage模式
- 多线程设计模式——Thread Confinement(串行线程封闭)模式
- 多线程设计模式:第四篇 - Thread-Per-Message模式和Worker-Thread模式
- Java多线程Thread-并发协作(生产者消费者设计模式)
- 基础 多线程 Thread synchronize 单例设计模式 死锁
- 多线程Thread-Specific Storage 模式
- 设计模式多线程方面之Thread-Per-Message 模式
- Thread(多线程,单例模式懒汉式)
- 多线程 Worker Thread 模式
- java多线程之Worker Thread模式
- java多线程Thread-per-Message模式详解
- JAVA多线程(九)模式-Thread Per Message
- Thread-Per-message Pattern--JAVA多线程编程模式(7)
- Java 多线程编程设计模式之 Thread Pool(线程池)
- ios笔记-- 多线程应该知道的那几件事 GCD NSThread NSOperation
- JAVA之旅(十二)——Thread,run和start的特点,线程运行状态,获取线程对象和名称,多线程实例演示,使用Runnable接口
- c++多线程基础2(命名空间 this_thread)
- 多线程单件模式-Java
- 初学Java多线程:用Thread类创建线程