美文网首页JavaJava多线程专题
[Java多线程编程之六] 线程封闭

[Java多线程编程之六] 线程封闭

作者: 小胡_鸭 | 来源:发表于2019-10-21 22:42 被阅读0次

    一、什么是线程封闭?

      多线程访问共享可变数据时,线程间执行顺序的不同可能导致程序运行结果的不同,即线程安全问题;所以在多线程环境下,不涉及到共享的数据,就要通过线程封闭防止数据被共享修改,将数据封闭在各自的线程之中,这种避免同步的技术就是线程封闭

    二、线程封闭的实现

    1、ThreadLocal

      ThreadLocal是Java中一种特别的线程级别的变量,当线程访问时,会为每个线程创建一个变量的副本,副本之间彼此独立,互不影响,从代码上看不同线程访问的是同一个变量,但实际上不同线程访问ThreadLocal时,获取到的封装其中的数据存储在不同的内存中,这保证了线程安全,代码示例如下:

    // 线程封闭示例
    public class Demo7 {
        /** threadLocal变量,每个线程都有一个副本,互不干扰 */
        public static ThreadLocal<String> value = new ThreadLocal<String>();
        
        public void threadLocalTest() throws Exception {        
            value.set("这是主线程设置的123");       // 主线程设置值
            String v = value.get();
            System.out.println("线程1执行之前,主线程取到的值:" + v);
            
            new Thread(new Runnable() {
                @Override
                public void run() {
                    String v = value.get();
                    System.out.println("线程1取到的值:" + v);
                    // 设置threadLocal
                    value.set("这是线程1设置的456");
                    
                    v = value.get();
                    System.out.println("重新设置之后,线程1取到的值:" + v);
                    System.out.println("线程1执行结束");
                }
            }).start();
            
            Thread.sleep(5000L);    // 等待所有线程执行结束
            v = value.get();
            System.out.println("线程1执行之后,主线程取到的值:" + v);
        }
        
        public static void main(String[] args) throws Exception {
            new Demo7().threadLocalTest();
        }
    }
    

    【代码解析】代码中有两个线程:主线程和匿名线程(姑且将其称为线程1),主线程率先访问ThreadLocal变量并设置其包装的String对象的值为 这是主线程设置的123 打印输出设置后的效果;接着执行线程1,线程1也去访问ThreadLocal,但是它拿到的数据值是空的,因为此时JVM为线程1中的ThreadLocal包装的数据分配了一个新的内存,接着线程1设置值并打印出来;线程1执行结束后,回到主线程,打印出来的值依然是执行线程1前主线程设置的值,说明两个线程对ThreadLocal的读取和设置操作是隔离的,互不影响。

    执行结果:


    如何理解ThreadLocal是一种线程级别的变量?

      每个线程都会有自己的栈,正常情况下多个线程访问一个共享对象时,是在自己的栈中持有对这个对象的引用,指向堆内存中的内存对象,如图所示:



      而当线程访问的是ThreadLocal时,ThreadLocal会为每个线程单独创建一个对象,不同线程对持有的对象进行操作互不干扰,也无法通过线程发布,是一种绝对安全的线程隔离,保证线程安全,如图所示:



      从某种程度上看,ThreadLocal可以看成是线程跟数据对象映射的Map,即Map<Thread, T>,每个线程读取数据时就通过当前线程去map里面get,从这个角度看,
    threadLocal.get() = map.get(Thread.currentThread())
    threadLocal.set(obj) = map.put(Thread.currentThread(), obj)
    
    2、局部变量

      局部变量被封闭在线程的栈中,而线程栈是属于线程私有的内存区域,因此其他线程无法访问,从而保证线程安全,常见的局部变量有方法中的局部变量,循环中的局部变量等。

    public void fun() {
        String str = ...;
    }
    
    while (true) {
        String str = ...;
    }
    
    for (int i = 0; i < length: i++) {
        int j = ...;
    }
    

    相关文章

      网友评论

        本文标题:[Java多线程编程之六] 线程封闭

        本文链接:https://www.haomeiwen.com/subject/zemmmctx.html