threadlocal是什么,Java:ThreadLocal究竟有什么用呢?费解
threadlocal是什么,Java:ThreadLocal究竟有什么用呢?费解详细介绍
本文目录一览: ThreadLocal的使用方法是什么?
早在Java 1.2推出之时,Java平台中就引入了一个新的支持:java.lang.ThreadLocal,给我们在编写多线程程序时提供了一种新的选择。使用这个工具类可以很简洁地编写出优美的多线程程序,虽然ThreadLocal非常有用,但是似乎现在了解它、使用它的朋友还不多。 ThreadLocal是什么 ThreadLocal是什么呢?其实ThreadLocal并非是一个线程的本地实现版本,它并不是一个Thread,而是thread local variable(线程局部变量)。也许把它命名为ThreadLocalVar更加合适。线程局部变量(ThreadLocal)其实的功用非常简单,就是为每一个使用该变量的线程都提供一个变量值的副本,是每一个线程都可以独立地改变自己的副本,而不会和其它线程的副本冲突。从线程的角度看,就好像每一个线程都完全拥有该变量。线程局部变量并不是Java的新发明,在其它的一些语言编译器实现(如IBM XL FORTRAN)中,它在语言的层次提供了直接的支持。因为Java中没有提供在语言层次的直接支持,而是提供了一个ThreadLocal的类来提供支持,所以,在Java中编写线程局部变量的代码相对比较笨拙,这也许是线程局部变量没有在Java中得到很好的普及的一个原因吧。 ThreadLocal的设计 首先看看ThreadLocal的接口: Object get() ; // 返回当前线程的线程局部变量副本 protected Object initialValue(); // 返回该线程局部变量的当前线程的初始值 void set(Object value); // 设置当前线程的线程局部变量副本的值 ThreadLocal有3个方法,其中值得注意的是initialValue(),该方法是一个protected的方法,显然是为了子类重写而特意实现的。该方法返回当前线程在该线程局部变量的初始值,这个方法是一个延迟调用方法,在一个线程第1次调用get()或者set(Object)时才执行,并且仅执行1次。ThreadLocal中的确实实现直接返回一个null: protected Object initialValue() { return null; } ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单,在ThreadLocal类中有一个Map,用于存储每一个线程的变量的副本。比如下面的示例实现: public class ThreadLocal { private Map values = Collections.synchronizedMap(new HashMap()); public Object get() { Thread curThread = Thread.currentThread(); Object o = values.get(curThread); if (o == null && !values.containsKey(curThread)) { o = initialValue(); values.put(curThread, o); } return o; } public void set(Object newValue) { values.put(Thread.currentThread(), newValue); } public Object initialValue() { return null; } } 当然,这并不是一个工业强度的实现,但JDK中的ThreadLocal的实现总体思路也类似于此。 ThreadLocal的使用 如果希望线程局部变量初始化其它值,那么需要自己实现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,这将极大地简化你的程序,使程序更加易读、简洁。
threadlocal使用场景和原理是什么?
threadlocal使用场景和原理是每个线程需要有自己单独的实例,实例需要在多个方法中共享,但不希望被多线程共享。线程同步正好相反,线程同步机制都是为了解决多线程中相同变量的访问冲突问题。线程同步机制需要保证多个线程都能准确的获取到共享变量的实时值,而ThreadLocal是只关心自己线程的副本。
threadlocal概况
ThreadLocal是线程本地变量的意思,即可以将变量控制在当前线程中,这样就避免了多线程并发的复杂处理,Spring中就有大量使用。为解决多线程访问共同变量时出现并发问题,例如多个线程对同一变量的写入操作,为了保护线程安全,一般需要额外同步措施。
什么是ThreadLocal?解决了什么问题?
首先加深印象: 1.ThreadLocal解决的是每个线程需要有自己独立的实例,且这个实例的修改不会影响到其他线程。 这个ThreadLocal的用法一般都是创建各自线程自己运行过程中单独创建的对象的,不适合的相同实例共享的。 https://ask.csdn.net/questions/764337 ThreadLocal存入的对象就不该是同一个。这玩意不保证线程安全。 所谓的副本是指,A线程存入的值,对B线程并不感知,B只能拿到自己存的值,并不能拿到A存入的值。 因为一般情况下ThreadLocal 都是定义为static类型的,如果没有ThreadLocal,那么B线程就可以获取A线程所存入的值。 理解了使用场景,很多地方就能想通了
2.ThreadLocal造成内存泄漏的问题我认为有两点:
ThreadLocal原理总结 1.每个Thread维护着一个ThreadLocalMap的引用
2.ThreadLocalMap是ThreadLocal的内部类,用Entry来进行存储
3.调用ThreadLocal的set()方法时,实际上就是往ThreadLocalMap设置值,key是ThreadLocal对象,值是传递进来的对象
4.调用ThreadLocal的get()方法时,实际上就是往ThreadLocalMap获取值,key是ThreadLocal对象
5.ThreadLocal本身并不存储值,它只是作为一个key来让线程从ThreadLocalMap获取value。
这里放出一个程序可以思考一下会输出什么?
答案是
可以debug来看一下他的流程
第一次set,由于Thread中的map还没有被初始化,所以先创建map
因为第一个ThreadLocal已经初始化了map,所以map!=null为true,
到此为止,上面的程序也好理解了,
Java:ThreadLocal究竟有什么用呢?费解
ThreadLocal不是用来解决对象共享访问问题的,而主要是提供了保持对象的方法和避免参数传递的方便的对象访问方式。归纳了两点:
1。每个线程中都有一个自己的ThreadLocalMap类对象,可以将线程自己的对象保持到其中,各管各的,线程可以正确的访问到自己的对象。
2。将一个共用的ThreadLocal静态实例作为key,将不同对象的引用保存到不同线程的ThreadLocalMap中,然后在线程执行
的各处通过这个静态ThreadLocal实例的get()方法取得自己线程保存的那个对象,避免了将这个对象作为参数传递的麻烦。
ThreadLocal的应用场合,我觉得最适合的是按线程多实例(每个线程对应一个实例)的对象的访问,并且这个对象很多地方都要用到。
ThreadLocal是对多线程而言的,用了ThreadLocal后,不会有线程安全问题。
从如下8点来讲解一下:
1.ThreadLocal用来解决多线程程序的并发问题
2.ThreadLocal并不是一个Thread,而是Thread的局部变量,当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每个线程都
可以独立地改变自己的副本,而不会影响其它线程所对应的副本.
3.从线程的角度看,目标变量就象是线程的本地变量,这也是类名中“Local”所要表达的意思。
4.线程局部变量并不是Java的新发明,Java没有提供在语言级支持(语法上),而是变相地通过ThreadLocal的类提供支持.
5.ThreadLocal类中的方法:(JDK5版本之后支持泛型)
void set(T value)
将此线程局部变量的当前线程副本中的值设置为指定值
void remove()
移除此线程局部变量当前线程的值
protected T initialValue()
返回此线程局部变量的当前线程的“初始值”
T get()
返回此线程局部变量的当前线程副本中的值
6.ThreadLocal的原理:
ThreadLocal是如何做到为每一个线程维护变量的副本的呢?其实实现的思路很简单:在ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素
的键为线程对象,而值对应线程的变量副本
7.自己模拟ThreadLocal:
public class SimpleThreadLocal{
private Map valueMap=Collections.synchronizedMap(new HashMap());
public void set(Object newValue){
valueMap.put(Thread.currentThread(),newValue);//键为线程对象,值为本线程的变量副本
}
public Object get(){
Thread currentThread=Thread.currentThread();
Object o=valueMap.get(currentThread);//返回本线程对应的变量
if(o==null&&!valueMap.containsKey(currentThread)){
//如果在Map中不存在,放到Map中保存起来
o=initialValue();
valueMap.put(currentThread,o);
}
return o;
}
public void remove(){
valueMap.remove(Thread.currentThread());
}
public void initialValue(){
return null;
}
}
8.使用ThreadLocal的具体例子:
public class SequenceNumber{
//通过匿名内部类覆盖ThreadLocal的initialValue()方法,指定初始值
private static ThreadLocal
seNum=new ThreadLocal
(){
protected Integer initialValue(){
return 0;
}
}
public Integer getNextNum(){
seNum.set(seNum.get()+1);
return seNum.get();
}
public static void main(String[] args){
SequenceNumber sn=new SequenceNumber();
//3个线程共享sn,各自产生序列号
TestClient t1 = new TestClient(sn);
TestClient t2 = new TestClient(sn);
TestClient t3 = new TestClient(sn);
t1.start();
t2.start();
t3.start();
}
private static class TestClient extends Thread{
private SequenceNumber sn;
public TestClient(SequenceNumber sn){
this.sn=sn;
}
public void run(){
//每个线程打印3个序列号
for(int i=0;i<3;i++){
System.out.println("thread["+Thread.currentThread().getName()+",sn["+sn.getNextNum()+"]");
}
}
}
}
什么是 ThreadLocal 类?ThreadLocal 是一个线程级别的局部变量如何理解?
ThreadLocal变量就是和线程绑定的变量.实际上是一个Map,,,key是对应的线程,值则是该变量.
调用ThreadLocal的get方法时则会到Map中查询当前线程是否已拥有该变量,如果没有则新建一个并保存到Map中.有的话直接返回与该线程绑定的变量.
说白了就是每个线程拥有不同的实例.以空间换时间.
threadLocal是要解决什么问题?在什么应用场景下使用呢
ThreadLocal 实例通常是类中的私有静态字段,一般用于存储与线程关联的局部变量。
这是个DB工具类,看明白你就知道了。
public class DB { private static DataSource ds; private static ThreadLocal
threadLocal = new ThreadLocal
(); static { ds = new ComboPooledDataSource(); } //防止实例 private DB(){ } public static DataSource getDataSource() { return ds; } /*** * 从连接池获取conn连接 * @return */ public static Connection getConnection() { try { // 得到当前线程上绑定的连接 Connection conn = threadLocal.get(); if (conn == null) { // 代表线程上没有绑定连接 conn = ds.getConnection(); threadLocal.set(conn); } return conn; } catch (Exception e) { throw new RuntimeException(e); } } /*** * 开启事务 */ public static void beginTransaction() { try { // 得到当前线程上绑定连接开启事务 Connection conn = getConnection(); if(!conn.getAutoCommit()){ logger.warn(" connection got the last autoCommit value ! "); } conn.setAutoCommit(false); } catch (Exception e) { throw new RuntimeException(e); } } /** * 提交事务 */ public static void commitTransaction() { try { Connection conn = threadLocal.get(); if (conn != null) { conn.commit(); } } catch (Exception e) { throw new RuntimeException(e); } } /*** * 关闭连接 */ public static void closeConnection() { try { Connection conn = threadLocal.get(); if (conn != null) { conn.close(); } } catch (Exception e) { throw new RuntimeException(e); } finally { threadLocal.remove(); } } /*** * 关闭连接 */ public static void rollback() { try { Connection conn = threadLocal.get(); if (conn != null) { conn.rollback();; } } catch (Exception e) { throw new RuntimeException(e); } }}
threadLocal是要解决什么问题
ThreadLocal不是用来解决对象共享访问问题的,而主要是提供了线程保持对象的方法和避免参数传递的方便的对象访问方式
ThreadLocal的应用场合,最适合的是按线程多实例(每个线程对应一个实例)的对象的访问,并且这个对象很多地方都要用到。
ThreadLocal不是用来解决对象共享访问问题的,而主要是提供了线程保持对象的方法和避免参数传递的方便的对象访问方式
ThreadLocal的应用场合,最适合的是按线程多实例(每个线程对应一个实例)的对象的访问,并且这个对象很多地方都要用到。
threadlocal原理是什么?
它主要由四个方法组成initialValue(),get(),set(T),remove(),其中值得注意的是initialValue(),该方法是一个protected的方法,显然是为了子类重写而特意实现的。
该方法返回当前线程在该线程局部变量的初始值,这个方法是一个延迟调用方法,在一个线程第1次调用get()时才执行,并且仅执行1次(即:最多在每次访问线程来获得每个线程局部变量时调用此方法一次,即线程第一次使用get()方法访问变量的时候。如果线程先于get方法调用set(T)方法,则不会在线程中再调用initialValue方法)。
相关信息:
ThreadLocal很容易让人望文生义,想当然地认为是一个“本地线程”。其实,ThreadLocal并不是一个Thread,而是Thread的局部变量,也许把它命名为ThreadLocalVariable更容易让人理解一些。
session的get根据当前线程返回其对应的线程内部变量,也就是我们需要的net.sf.hibernate.Session(相当于对应每个数据库连接).多线程情况下共享数据库链接是不安全的。ThreadLocal保证了每个线程都有自己的s(数据库连接)。
ThreadLocal 实现原理是什么 & 有哪些引用类型及使用场景?
对于一个 ThreadLocal 对象,通常会有两个引用指向它:
key 是弱引用,当不存在外部强引用时,会被自动回收。而 value 是强引用,引用链如下
所以只有当 Thread 被回收,value 才会被回收,否则 value 将一直存在,但是让每个线程关闭,是不现实的。在线程池中,大部分线程会伴随着系统的整个周期,那么 value 可能会造成泄漏。
解决方法,在 ThreadLocalMap 进行 set(),get(),remove() 的时候,都进行清理:
真正回收 value 的是 expungeStaleEntry() 方法,在 remove 和 set 方法中都会调用这个方法。
ThreadLocal 为了避免内存泄露,不仅使用了弱引用维护 key ,还在每个操作上检查 key 是否被回收,进而再回收value。
1、强引用
2、软引用
3、弱引用
4、虚引用