ThreadLocal的使用-java ThreadLocal学习笔记

2019-03-12 23:38|来源: 网络

如果希望线程局部变量初始化其它值,那么需要自己实现ThreadLocal的子类并重写该方法,通常使用一个内部匿名类对ThreadLocal进行子类化,比如下面的例子,SerialNum类为每一个类分配一个序号:

  public class SerialNum
  {
   // The next serial number to be assigned

   private static int nextSerialNum = 0;
   private static ThreadLocal serialNum = new ThreadLocal()
   {
   protected synchronized Object initialValue()
   {
    return new Integer(nextSerialNum++);
   }
   };

   public static int get()
   {
   return ((Integer) (serialNum.get())).intValue();
   }
  }

  SerialNum类的使用将非常地简单,因为get()方法是static的,所以在需要获取当前线程的序号时,简单地调用:

  int serial = SerialNum.get();

  即可。

   在线程是活动的并且ThreadLocal对象是可访问的时,该线程就持有一个到该线程局部变量副本的隐含引用,当该线程运行结束后,该线程拥有的所以线程局部变量的副本都将失效,并等待垃圾收集器收集。

   ThreadLocal与其它同步机制的比较

   ThreadLocal和其它同步机制相比有什么优势呢?ThreadLocal和其它所有的同步机制都是为了解决多线程中的对同一变量的访问冲突,在普通的同步机制中,是通过对象加锁来实现多个线程对同一变量的安全访问的。这时该变量是多个线程共享的,使用这种同步机制需要很细致地分析在什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放该对象的锁等等很多。所有这些都是因为多个线程共享了资源造成的。ThreadLocal就从另一个角度来解决多线程的并发访问,ThreadLocal会为每一个线程维护一个和该线程绑定的变量的副本,从而隔离了多个线程的数据,每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的共享对象,在编写多线程代码时,可以把不安全的整个变量封装进ThreadLocal,或者把该对象的特定于线程的状态封装进ThreadLocal。

   由于ThreadLocal中可以持有任何类型的对象,所以使用ThreadLocal get当前线程的值是需要进行强制类型转换。但随着新的Java版本(1.5)将模版的引入,新的支持模版参数的ThreadLocal类将从中受益。也可以减少强制类型转换,并将一些错误检查提前到了编译期,将一定程度地简化ThreadLocal的使用。

   总结

   当然ThreadLocal并不能替代同步机制,两者面向的问题领域不同。同步机制是为了同步多个线程对相同资源的并发访问,是为了多个线程之间进行通信的有效方式;而ThreadLocal是隔离多个线程的数据共享,从根本上就不在多个线程之间共享资源(变量),这样当然不需要对多个线程进行同步了。所以,如果你需要进行多个线程之间进行通信,则使用同步机制;如果需要隔离多个线程之间的共享冲突,可以使用ThreadLocal,这将极大地简化你的程序,使程序更加易读、简洁。


转自网络


相关问答

更多
  • SequenceNumber package com.baobaotao.basic; public class SequenceNumber { ①通过匿名内部类覆盖ThreadLocal的initialValue()方法,指定初始值 private static ThreadLocal seqNum = new ThreadLocal (){ public Integer initialValue(){ return 0; } }; ②获取下一个序列值 public int getNextNum(){ ...
  • 从如下8点来讲解一下: 1.ThreadLocal用来解决多线程程序的并发问题 2.ThreadLocal并不是一个Thread,而是Thread的局部变量,当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每个线程都 可以独立地改变自己的副本,而不会影响其它线程所对应的副本. 3.从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思。 4.线程局部变量并不是Java的新发明,Java没有提供在语言级支持(语法上), ...
  • 这是安全的,因为getMap返回给定(即当前)线程的映射。 没有其他线程会与此混淆。 所以它实际上getMap的实现,以确保任何线程都可以 - 并且据我所知,它只是委托给Thread对象中的一个字段。 我不清楚getMap是否传递了除当前线程之外的任何线程 - 如果是,那可能是getMap棘手的 - 但我怀疑它们都是经过仔细编写以确保不是问题:) It's safe because getMap returns the map for the given (i.e. current) thread. No ...
  • 这里的所有答案都是正确的,但有点令人失望,因为它们ThreadLocal了解ThreadLocal的实现方式。 我只是看看ThreadLocal的源代码,并对它的实现感到ThreadLocal 。 天真的实现 如果我要求您实现一个给定javadoc中描述的API的ThreadLocal类,那么你会怎么做? 最初的实现可能是使用Thread.currentThread()作为其键的ConcurrentHashMap 。 这将工作得很好,但确实有一些缺点。 线程争用 - Concurr ...
  • 因为如果它是一个实例级别的字段,那么它实际上是“Per Thread - Per Instance”,而不仅仅是一个保证的“Per Thread”。 这通常不是您要查找的语义。 通常它持有类似于用户对话,Web请求等范围的对象的东西。您不希望它们也被分配到类的实例。 一个Web请求=>一个持久性会话。 每个对象没有一个Web请求=>一个持久性会话。 Because if it were an instance level field, then it would actually be "Per Threa ...
  • 线程本地缓存副本很好,因为它更简单,更有效。 一个缓存副本,你不确定它是本地线程可能是一个问题。 单身定义意味着只能有一个。 我不会把你作为一个单身人物所拥有的,你每个线程都有一个。 我会在它的构造函数中初始化()你的线程局部对象。 BTW你的ThreadLocal应该是private static final我怀疑。 A thread local cached copy is fine as it is simpler and more efficient. A cached copy where you ...
  • 通过使用ThreadLocal,可以创建与线程一样多的变量,而无需进一步检查。 但请记住,存储本身并不能保证线程安全。 您必须确保存储在本地存储中的每个对象仅在该线程中使用! 如果您手动克隆对象,则每次使用对象时都必须克隆对象,或者检查我们是哪个线程,然后克隆。 此外 - 克隆操作是否线程安全? 如果两个不同的线程试图克隆一个对象会发生什么? 我其实不知道,但我认为这不是一个好的做法。 By using ThreadLocal you create as many variables as there ar ...
  • ThreadLocal的目的是这些字段不必是原子的 - 不需要将它们的值与集中式内存同步。 它们是线程本地的,只存在于线程本地存储器中。 为什么我会想要使用ThreadLocal而不是AtomicLong或AtomicInteger? ThreadLocal对于存储某个东西的每个线程副本非常有用。 例如SimpleDateFormat不幸是不可重入的。 private final ThreadLocal threadLocal = new ThreadLocal
  • 您的代码的问题是您将保持文件指针打开。 您可以将对象存储在ThreadLocal中,但不存储诸如文件句柄,数据库连接或其他需要关闭的资源等资源。 ThreadLocal将超出范围,因此一旦Thread完成就会被垃圾收集。 在您的情况下,我将存储您从ThreadLocal中的InputStream获取的内容,但不存储流本身。 如果您想确保某些内容始终可用,请使用Singleton模式。 请注意Java EE环境中模式的局限性。 The problem with your code is that you wi ...
  • ThreadLocal local = new ThreadLocal(); local.set("String"); System.out.println(local.get()); 您需要在ThreadLocalVariable中设置一些内容然后检索它。 最初,ThreadLocal为空。 ThreadLocal local = new ThreadLocal(); local.set("String"); System.out.prin ...