`
阅读更多

ThreadLocal和线程同步机制相比有什么优势呢?ThreadLocal和线程同步机制都是为了解决多线程中相同变量的访问冲突问题。

在同步机制中,通过对象的锁机制保证同一时间只有一个线程访问变量。这时该变量是多个线程共享的,使用同步机制要求程序缜密地分析什么时候对变量进行读写,什么时候需要锁定某个对象,什么时候释放对象锁等繁杂的问题,程序设计和编写难度相对较大。
概述:
而ThreadLocal则从另一个角度来解决多线程的并发访问。ThreadLocal为每一个线程提供一个独立的变量副本,从而隔离了多个线 程对访问数据的冲突。因为每一个线程都拥有自己的变量副本,从而也就没有必要对该变量进行同步了。ThreadLocal提供了线程安全的对象封装,在编 写多线程代码时,可以把不安全的变量封装进ThreadLocal。

由于ThreadLocal中可以持有任何类型的对象,低版本JDK所提供的get()返回的是Object对象,需要强制类型转换。但JDK 5.0通过泛型很好的解决了这个问题,在一定程度上简化ThreadLocal的使用,代码清单9-2就使用了JDK 5.0新的ThreadLocal<T>版本。

概括起来说,对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式:访问串行化,对象共享化。而ThreadLocal采用了“以空 间换时间”的方式:访问并行化,对象独享化。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影 响。

 

一:先说下ThreadLocal的作用总结吧:

        当线程并发时,使用ThreadLocal在保证每个线程拥有自己的独立对象,线程间互不影响。

 

二:在说下ThreadLocal和Synchronized关键字对线程并发时锁定同意操作对象的区别

        前者线程并发拥有自己独立对象,做到操作对象的安全,但是它每个线程都会new一个操作对象的实例,这样一来,就损失了系统耗费内存的问题,但是性能有所提升!(以空间换时间)

        后者线程并发时可以用Synchronized关键字来对线程来同步执行,但是它只能单个线程执行,阻塞其他线程,这样一来,就损失了系统的性能,但是系统内存占用问题有所提高!(以时间换空间)

 

三:我们来看下ThreadLocal应用的demo

public class Student {

    private int age = 0; // 年龄

    public int getAge() {
        return this.age;
    }

    public void setAge(int age) {
        this.age = age;
    }

}

public class ThreadLocalDemo implements Runnable {

    // 创建线程局部变量studentLocal,在后面你会发现用来保存Student对象
    private final static ThreadLocal studentLocal = new ThreadLocal();

    public static void main(String[] agrs) {
        ThreadLocalDemo td = new ThreadLocalDemo();
        Thread t1 = new Thread(td, "a");
        Thread t2 = new Thread(td, "b");
        t1.start();
        t2.start();
    }

    public void run() {
        // TODO Auto-generated method stub
        accessStudent();
    }

    public void accessStudent() {
        // 获取当前线程的名字
        String currentThreadName = Thread.currentThread().getName();
        System.out.println(currentThreadName + " is running!");
        // 产生一个随机数并打印
        Random random = new Random();
        int age = random.nextInt(100);
        System.out.println("thread " + currentThreadName + " set age to:" + age);
        // 获取一个Student对象,并将随机数年龄插入到对象属性中
        Student student = getStudent();
        student.setAge(age);
        System.out.println("thread " + currentThreadName + " first read age is:" + student.getAge());
        try {
            Thread.sleep(500);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
        System.out.println("thread " + currentThreadName + " second read age is:" + student.getAge());
    }

    protected Student getStudent() {
        // 获取本地线程变量并强制转换为Student类型
        Student student = (Student) studentLocal.get();
        // 线程首次执行此方法的时候,studentLocal.get()肯定为null
        if (student == null) {
            // 创建一个Student对象,并保存到本地线程变量studentLocal中
            student = new Student();
            studentLocal.set(student);
        }
        return student;
    }

}

a is running!
b is running!
thread b set age to:15
thread a set age to:22
thread b first read age is:15
thread a first read age is:22
thread b second read age is:15
thread a second read age is:2
// 从得到的结果可以看出,线程之间的Student对象在每个线程中都拥有一个,做到互不干扰!

 为加强对ThreadLocal的认识,下面来看一个hibernate中典型的ThreadLocal的应用:

    private static final ThreadLocal threadSession = new ThreadLocal();  
      
    public static Session getSession() throws InfrastructureException {  
        Session s = (Session) threadSession.get();  
        try {  
            if (s == null) {  
                s = getSessionFactory().openSession();  
                threadSession.set(s);  
            }  
        } catch (HibernateException ex) {  
            throw new InfrastructureException(ex);  
        }  
        return s;  
    }  

 我们通过以上例子,不难看出ThreadLocal的应用场合,最适合的是按线程多实例(每个线程对应一个实例)的对象的访问,并且这个对象很多地方都要用到。

                                          

最后补充下,ThreadLocal常用的方法

T get()
          返回此线程局部变量的当前线程副本中的值。
protected  T initialValue()
          返回此线程局部变量的当前线程的初始值。
void remove()
          移除此线程局部变量的值。
void set(T value)
          将此线程局部变量的当前线程副本中的值设置为指定值。

1
3
分享到:
评论
4 楼 zhangliguoaccp 2015-10-14  
我说的是ThreadLocal是消耗内存在控制多线程并发,对象共享问题,这才是他的精髓!
而你说的是回收的问题,但应用它也是要考虑回收问题的
3 楼 cywhoyi 2015-10-14  
zhangliguoaccp 写道
不是吧兄弟,ThreadLocal是消耗内存在控制多线程并发,对象共享问题,这才是他的精髓吧

stackoverflow exception,如果使用不当TL会经常抛出,一般用完要remove,或者像Tomcat那样通过配合线程池进行反复使用
2 楼 zhangliguoaccp 2015-10-13  
不是吧兄弟,ThreadLocal是消耗内存在控制多线程并发,对象共享问题,这才是他的精髓吧
1 楼 cywhoyi 2015-10-12  
ThreadLocal属于线程副本的变量,更多使用场景是内存消耗可控制,要不然TL的回收是大问题

相关推荐

    java ThreadLocal多线程专属的变量源码

    java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多线程专属的变量源码java ThreadLocal多...

    Java多线程 之 临界区、ThreadLocal.docx

    synchronized关键字不属于方法特征签名的一...注意:使用synchronized是对哪个对象加的锁。 如果在一个类内部都是使用synchronized关键字定义了方法f(),g()。那么当使用这个类的实例调用f()时,就不能再调用g()方法。

    java线程详解

    Java线程:概念与原理 Java线程:创建与启动 Java线程:线程状态的转换 Java线程:线程的同步与锁 一、同步问题提出 二、同步和锁定 三、静态方法同步 四、如果线程不能不能获得锁会怎么样 ...Java线程:大总结

    Java多线程与并发库高级应用视频教程22集

    资源名称:Java多线程与并发库高级应用视频教程22集资源目录:【】01传统线程技术回顾【】02传统定时器技术回顾【】03传统线程互斥技术【】04传统线程同步通信技术【】04传统线程同步通信技术_分割纪录【】05线程...

    java核心知识点学习----多线程间的数据共享和对象独立,ThreadLocal详解.pdf

    java核心知识点学习----多线程间的数据共享和对象独立,ThreadLocal详解.pdf

    Java多线程编程中ThreadLocal类的用法及深入

    早在 JDK 1.2 的时代,java.lang.ThreadLocal 就诞生了,它是为了解决多线程并发问题而设计的,只不过设计得有些难用,所以至今没有得到广泛使用。其实它还是挺有用的,不相信的话,我们一起来看看这个例子吧。 一个...

    Java高级程序设计-多线程(二).pptx

    掌握同步方法的使用 理解线程死锁 掌握 ThreadLocal 类的使用 使用多线程模拟猴子采花 使用同步方法模拟购票 使用多线程模拟购物订单生成 使用 ThreadLocal 类模拟银行取款 Java高级程序设计-多线程(二)全文共34页,...

    Java多线程编程之ThreadLocal线程范围内的共享变量

    主要介绍了Java多线程编程之ThreadLocal线程范围内的共享变量,本文讲解了ThreadLocal的作用和目的、ThreadLocal的应用场景、ThreadLocal的使用实例等,需要的朋友可以参考下

    java多线程安全性基础介绍.pptx

    java多线程安全性基础介绍 线程安全 正确性 什么是线程安全性 原子性 竞态条件 i++ 读i ++ 值写回i 可见性 JMM 由于cpu和内存加载速度的差距,在两者之间增加了多级缓存导致,内存并不能直接对cpu可见。 ...

    53.线程间的通信-join方法-ThreadLocal类.mp4

    在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。

    ThreadLocal详解

    java 多线程 ThreadLocal

    基础技术部牛路《Java多线程入阶分享》纯干货

    Java多线程入阶干货分享 1.使用线程的经验:设置名称、响应中断、使用ThreadLocal 2.Executor:ExecutorService和Future 3.阻塞队列:put和take、offer和poll、drainTo 4.线程间通信:lock、condition、wait、notify...

    举例解析Java多线程编程中需要注意的一些关键点

    主要介绍了Java多线程编程中需要注意的一些关键点,包括ThreadLocal变量与原子更新等一些深层次的内容,需要的朋友可以参考下

    Java多线程源码笔记.pdf

    1.什么是多线程 2.Thread类解析 3.使用多线程需要注意的问题 4.synchronized锁和lock锁 5.AQS 6.ReentrantLock和ReentrantReadWriteLock 7.线程池 8.死锁 9.线程常用的工具栏 10.Atomic 11.ThreadLocal

    Quartz-ThreadLocal.rar

    本地学习练习demo的eclipse工作空间:主要包括多线程的相关demo以及quartz调度的简单实现和其他java基础的demo练习

    java8源码-geektime-java-common-mistakes:geektime-java-常见错误

    不能认为没有显式开启多线程就不会有线程安全问题。 在 Tomcat 这种 Web 服务器下跑的业务代码,本来就运行在一个多线程环境。 Tomcat 的工作线程是基于线程池的。 线程池会重用固定的几个线程,一旦线程重用,那么...

    【2018最新最详细】并发多线程教程

    【2018最新最详细】并发多线程教程,课程结构如下 1.并发编程的优缺点 2.线程的状态转换以及基本操作 3.java内存模型以及happens-before规则 4.彻底理解synchronized 5.彻底理解volatile 6.你以为你真的了解final吗...

    java线程本地变量ThreadLocal详解

    ThreadLocal则为每一个线程提供了一个变量副本,从而隔离了多个线程访问数据的冲突,ThreadLocal提供了线程安全的对象封装,下面我们就来详细了解一下吧

    基于Java多线程同步的安全性研究

    解决Java多线程同步的方法是在需要同步的方法签名中加入synchronized关键字,使用synchronized对需要进行同步的代码段进行同步,或使用JDK 5中提供的java.util.concurrent.lock包中的Lock对象。为解决多个线程对同一...

Global site tag (gtag.js) - Google Analytics