据我所知,在Java中,ThreadLocal类使我们能够创建虚拟线程范围。因此,线程无法访问其他变量或其他内容。
请你给一些编码器需要使用ThreadLocal的代码,在使用ThreadLocal之后一切正常。
感谢。
答案 0 :(得分:1)
一个常见的例子是使用DateFormat
(或Random
,但现在它有自己的ThreadLocalRandom
类。
该类不是线程安全的,但每次需要时都需要时间来创建一个新对象。
创建ThreadLocal<DateFormat>
时,您可以确保每个帖子都有自己可以安全使用的DateFormat
,并且不会有不必要的性能点击。
答案 1 :(得分:1)
在幕后,当创建一个ThreadLocal对象时,它实际上会在内部创建一个HashMap,如下所示:
HashMap<ThreadID,Value> map;
所以当一个特定的线程向Thread Local对象添加一个值时,它会将当前线程的ThreadId作为“key”插入,并将值作为“value”插入HashMap中。
map.put(thread.currentthread().getid() , Value );
所以当我们从Thread Local对象获取值时,它将执行以下操作:
map.get(thread.currentthread().getid());
所以我们甚至认为我们只创建一个ThreadLOcal对象的实例,但是我们将能够将它们作为每个Thread的本地实例。
请检查下面的代码。
我们通过将runnable对象传递给它来创建3个线程,并且我们还在构造函数本身中设置每个线程的名称。
在thr run()方法中,我们将ThreadName设置为Thread Local对象,并将线程放入sleep(),同时,其他线程可以进入run()方法并再次将其thraedName设置为SAME线程Local实例
一旦线程处于唤醒状态,我们将从Thread Local对象中取回数据并将其打印出来......
public class ThreadLocalDemo {
public static void main(String[] args) {
testLocal oneInstance = new testLocal();
Thread A = new Thread(oneInstance);
Thread B = new Thread(oneInstance);
Thread C = new Thread(oneInstance);
A.start();
try
{
Thread.sleep(400);
}
catch(InterruptedException e){}
B.start();
try
{
Thread.sleep(400);
}
catch(InterruptedException e){}
C.start();
try
{
Thread.sleep(400);
}
catch(InterruptedException e){}
}
}
class testLocal implements Runnable
{
private static final ThreadLocal local = new ThreadLocal<String>(){
@Override
protected String initialValue() {
System.out.println(" local thread initialValue() called ");
return "intial Value";
}
};
@Override
public void run() {
local.set(Thread.currentThread().getName());
try
{
Thread.sleep(2000);
}
catch(InterruptedException e){}
System.out.print(Thread.currentThread().getName() + " run() " );
System.out.print(" called.... ");
System.out.println(local.get());
}
}
答案 2 :(得分:1)
使用ThreadLocal
是一种为每个线程提供信息的便捷方式,通常用于Web应用程序,其中模型是每个请求一个线程。需要针对每个请求单独跟踪的请求上下文数据可以使用ThreadLocal
提供。
ThreadLocal
通常用于Spring Framework,根据所使用的组件,您可以使用ThreadLocal
表示各种类型的上下文。
有关真实世界的示例,请参阅:
这些示例中的每个示例的意图和实现都是类似的。例如您想要存储当前请求的Locale
信息,然后将其提供给其他地方。 set方法(例如setLocaleContext
将信息存储在ThreadLocal上)和get方法(例如getLocaleContext
将返回当前请求中的Locale
信息)
最后,我想补充一点,滥用ThreadLocal
不是一个好主意,不应该被视为优秀设计的替代品。因此,如果相关的上下文信息可以通过传递具有适当字段值的对象来共享,那么这应该优先于ThreadLocal
s,这使得信息可以被普遍访问。 This article可能更有用。
答案 3 :(得分:0)
您可以将任何非线程安全单元包装到ThreadLocal中以使其线程安全。例如Java的SimpleDateFormat API,它不是线程安全的,但您可以使用以下代码片段使其成为线程安全
private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){
@Override
protected SimpleDateFormat initialValue()
{
return new SimpleDateFormat("yyyyMMdd HHmm");
}
};
答案 4 :(得分:0)
private DateFormat df = new SimpleDateFormat("dd/MM/yyyy");
public String formatFirstDate() {
return df.format(new Date());
}
public String formatSecondDate() {
return df.format(new Date(0));
}
在上面的代码中,如果两个线程同时调用formatFirstDate()和formatSecondDate(),可能会导致混乱的结果,因为DateFormat对象不是线程安全的。使用线程本地可以解决此问题: -
public static ThreadLocal df = new ThreadLocal() {
protected DateFormat initialValue() {
return new SimpleDateFormat("dd/MM/yyyy");
}
};
public String formatFirstDate() {
return df.get().format(new Date());
}
public String formatSecondDate() {
return df.get().format(new Date(0));
}
答案 5 :(得分:0)
仅供参考Yathish Manjunath的答案。
因此,当特定线程向线程本地对象添加值时,它将在HashMap中插入当前线程的 ThreadId 作为“键”,并将Value作为“值”。
在 Java 8 中,线程具有threadLocals
字段,该字段是ThreadLocal.ThreadLocalMap
的实例,因为每个线程局部变量的键都是线程局部实例本身。
摘录自ThreadLocal.java
的代码段。
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value); <------ this as the key
else
createMap(t, value);
}
ThreadLocal变量和Thread变量总共唯一地确定缓存的变量:值。