zoukankan      html  css  js  c++  java
  • ThreadLocal学习

    一、简介

      ThreadLocal的引入,在多线程情况下,实现线程变量的共享,但是又不相互影响,也就是所说的线程隔离。

      下面是非线程安全的方法实现

     1 package com.volshell.threads;
     2 
     3 import java.util.Date;
     4 import java.util.concurrent.TimeUnit;
     5 
     6 public class UnsafeTask implements Runnable {
     7     private Date startDate;
     8 
     9     @Override
    10     public void run() {
    11         // TODO Auto-generated method stub
    12         startDate = new Date();
    13         System.out.println("Start thread :" + Thread.currentThread().getId()
    14                 + ": " + startDate);
    15 
    16         try {
    17             TimeUnit.SECONDS.sleep((int) Math.rint(Math.random() * 10));
    18         } catch (InterruptedException e) {
    19             // TODO Auto-generated catch block
    20             e.printStackTrace();
    21         }
    22 
    23         System.out.println("Thread finished :" + Thread.currentThread().getId()
    24                 + "--" + startDate);
    25     }
    26 
    27 }

      测试代码:

    package com.volshell.threads.test;
    
    import java.util.concurrent.TimeUnit;
    
    import com.volshell.threads.UnsafeTask;
    
    public class UnsafeTaskTest {
        public static void main(String[] args) throws InterruptedException {
            UnsafeTask task = new UnsafeTask();
    
            for (int i = 0; i < 10; i++) {
                Thread t = new Thread(task);
                t.start();
    
                TimeUnit.SECONDS.sleep(2);
            }
        }
    }

    按照一般思路理解每个线程结束的时间和开始的时间是不相同的,但是有些线程有相同的结束时间!!

      下面是通过使用线程局部变量加以控制的,ThreadLocal

    package com.volshell.threads;
    
    import java.util.Date;
    import java.util.concurrent.TimeUnit;
    
    public class SafeTask implements Runnable {
        private static ThreadLocal<Date> startDate = new ThreadLocal<Date>() {
            protected Date initialValue() {
                return new Date();
            };
        };
    
        @Override
        public void run() {
            // TODO Auto-generated method stub
        
            System.out.println("Start thread :" + Thread.currentThread().getId()
                    + ": " + startDate.get());
    
            try {
                TimeUnit.SECONDS.sleep((int) Math.rint(Math.random() * 10));
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
            System.out.println("----------Thread finished :" + Thread.currentThread().getId()
                    + "--" + startDate.get());
        }
    
    }

    这样,每一个线程的起始、结束时间就完全不一样了。

    二、深入源码

      ThreadLocal类提供了thread-local variables ,通过set/get方法实现对变量的初始化。在第一次调用set的时候完成初始化。

      get方法

        public T get() {
            Thread t = Thread.currentThread();
            ThreadLocalMap map = getMap(t);
            if (map != null) {
                ThreadLocalMap.Entry e = map.getEntry(this);
                if (e != null)
                    return (T)e.value;
            }
            return setInitialValue();
        }

      其实在其内部维护一个Map -- ThreadLocalMap,其内部同样适用Entry来实现,每一个线程用一个Entry存储。

            static class Entry extends WeakReference<ThreadLocal> {
                /** The value associated with this ThreadLocal. */
                Object value;
    
                Entry(ThreadLocal k, Object v) {
                    super(k);
                    value = v;
                }
            }

      不过他的key为ThreadLocal对象。

      回到get方法,通过当前线程获取ThreadLocalMap对象, ThreadLocalMap.Entry e = map.getEntry(this); 获取当前线程的Entry,然后就可以得到value.

      set方法与之类似,

    三、总结

      每一个线程对应着一个ThreadLocalMap,Map中存储着Entry,而Entry中的key为ThreadLocal对象,value为真实的线程私有变量。

  • 相关阅读:
    阿里云 k8s 部署 Spring Cloud Alibaba 微服务实践 (四) 自动化部署
    阿里云 k8s 部署 Spring Cloud Alibaba 微服务实践 (三) 服务观测
    阿里云 k8s 部署 Spring Cloud Alibaba 微服务实践 (二) 部署微服务程序
    阿里云 k8s 部署 Spring Cloud Alibaba 微服务实践 (一) 部署 Nacos
    C++知识点
    libmkl 学习笔记
    基于tesseract-OCR进行中文识别
    poco编译与运行
    Linux下的I/O复用与epoll详解(转载)
    高并发网络编程之epoll详解(转载)
  • 原文地址:https://www.cnblogs.com/plxx/p/4813054.html
Copyright © 2011-2022 走看看