显示ThreadLocal使用要求的示例

时间:2015-08-04 08:38:52

标签: java multithreading thread-safety thread-local

据我所知,在Java中,ThreadLocal类使我们能够创建虚拟线程范围。因此,线程无法访问其他变量或其他内容。

请你给一些编码器需要使用ThreadLocal的代码,在使用ThreadLocal之后一切正常。

感谢。

6 个答案:

答案 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变量总共唯一地确定缓存的变量:值。