Thread-Specific-Storage模式

Thread-Specific-Storage模式

Thread-Specific-Storage是一种即使只有一个入口,也会在内部为每个线程分配特有的存储空间的模式。

在Java标准类库中,java.lang.ThreadLocal类实现了该模式。

关于ThreadLocal类

java.lang.ThreadLocal就是储物间

将java.lang.ThreadLocal的实例当做一种集合可能会有助于大家理解它。也就是说,一个ThreadLocal的实例会管理多个对象。

由于一个ThreadLocal的实例可以管理多个多想,所有ThreadLocal定义了可以“存储”(set)和“获取”(get)对象的方法。

Set方法

ThreadLocal类的set方法用于将通过参数接受的实例与调用该方法的线程(当前线程)对应并存储起来。这里存储的对象可以通过get方法获取。set方法中没有表示线程的参数。set方法会先查询当前线程(即表达式Thread.currentThread()的值),然后以它作为键来存储实例。

get方法

ThreadLocal类的get方法用于获取与调用get方法的线程(当前线程)对应的实例。该线程之前通过set方法存储的实例就是get方法的返回值。如果之前一次都还没有调用过set方法,则get方法的返回值为null。

与set方法一样,get方法中也没有表示线程的参数。这是因为,get方法也回去查询当前线程。即get方法会以当前线程自身作为键取获取对象。

java.lang.ThreadLocal与泛型

java.lang.ThreadLocal是一个泛型类,可以通过参数的类型来指定要存储的对象的类型。ThreadLocal类的声明大致如下:

1
2
3
4
5
6
7
public class ThreadLocal<T> {
public void set(T value) {
}

public T get() {
}
}

即,通过ThreadLocal的T指定的类型就是set方法的参数的类型以及get方法的返回值的类型。

类的一览表

名字 说明
TsLog 创建日志的类(实例属于各个线程所有)
Log 创建日志的类(分配各个线程)
java.lang.ThreadLocal 分配线程特有的存储空间的类
ClientThread 表示调用Log的线程的类
Main 测试程序行为的类

TSLog类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public class TSLog {
private PrintWriter printWriter = null;

public TSLog(String fileName) {
try {
printWriter = new PrintWriter(new FileWriter(fileName));
} catch (IOException e) {
e.printStackTrace();
}
}

public void println(String s) {
printWriter.println(s);
}

public void close() {
printWriter.println("==== End of log ====");
printWriter.close();
}
}

Log类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

public class Log {
private static final ThreadLocal<TSLog> tsLogCollection = new ThreadLocal<>();

public static void println(String s) {
getTSLog().println(s);
}

public static void close() {
getTSLog().close();
}

private static TSLog getTSLog() {
TSLog tsLog = tsLogCollection.get();

if (null == tsLog) {
tsLog = new TSLog(Thread.currentThread().getName() + "-log.txt");
tsLogCollection.set(tsLog);
}
return tsLog;
}
}

ClientThread类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class ClientThread extends Thread {
public ClientThread(String name) {
super(name);
}

public void run() {
System.out.println(getName() + " Begin");
for (int i = 0;i < 10;i++) {
Log.println("i = " + i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Log.close();
System.out.println(getName() + " End");
}

}

Main类

1
2
3
4
5
6
7
public class Main {
public static void main(String[] args) {
new ClientThread("A").start();
new ClientThread("B").start();
new ClientThread("C").start();
}
}
0%