• 多线程学习 ThreadLocal的使用。


      ThreadLocal ,即线程变量,是一个以ThreadLocal对象为键,任意对象为值得存储接口。这个接口被附带在线程上,也就是说一个线程可以根据一个ThreadLocal对象查询到绑定在这个线程上的值。

      可以通过set(T)方法来设置一个值,在当前线程下,在通过get()方法获取到原先设置的值。

      上面的文字是不是有点晦涩?来,学习一下明白的。

      变量值得共享可以使用 public static 变量的形式,所有的线程都使用同一个 public static 变量。如果想实现每一个线程都有自己的共享变量该如何解决那?

      jdk提供了ThreadLocal正是为了解决这样的问题。  

      类ThreadLocal 主要解决的就是每个线程绑定自己的值,可以将ThreadLocal类比喻成全局存放数据的盒子,盒子中可以存储每个线程的私有数据。

      

      下面实验:

      1 创建ThreadLocal对象,用来存储每个线程的私有值。

      

    public class Tools {
    
    	public static ThreadLocal t=new ThreadLocal();
    }
    

      2 创建两个线程A,B.

      

    public class ThreadA extends Thread {
    
    	@Override
    	public void run() {
    		super.run();
    		try {
    			for(int i=0;i<100;i++){
    				Tools.t.set("ThreadA "+(i+1));
    				System.out.println("ThreadA get Value " + Tools.t.get());
    				Thread.sleep(200);
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    

      

    public class ThreadB extends Thread{
    
    	@Override
    	public void run() {
    		super.run();
    		try {
    			for(int i=0;i<100;i++){
    				Tools.t.set("ThreadB "+(i+1));
    				System.out.println("ThreadB get Value "+Tools.t.get());
    				Thread.sleep(200);
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    

      主线程:

    public class Run {
    
    	public static void main(String[] args) {
    		
    		try {
    			ThreadA a=new ThreadA();
    			ThreadB b=new ThreadB();
    			a.start();
    			b.start();
    			
    			for (int i = 0; i < 100; i++) {
    				Tools.t.set("main "+(i+1));
    				System.out.println("main get Value "+Tools.t.get());
    				Thread.sleep(200);
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    
    	}
    
    }
    

      控制台:

    ThreadB get Value ThreadB 1
    ThreadA get Value ThreadA 1
    main get Value main 1
    ThreadA get Value ThreadA 2
    main get Value main 2
    ThreadB get Value ThreadB 2
    main get Value main 3
    ThreadA get Value ThreadA 3
    ThreadB get Value ThreadB 3
    ThreadA get Value ThreadA 4
    ThreadB get Value ThreadB 4
    main get Value main 4
    ThreadB get Value ThreadB 5
    ThreadA get Value ThreadA 5
    main get Value main 5
    main get Value main 6
    ThreadB get Value ThreadB 6
    ThreadA get Value ThreadA 6
    

      可以发现,ThreadA,ThreadB,和主线程三个在ThreadLocal中存储的值互不影响,每个线程增加,取值,都是自己的私有的。ThreadLocal中存储的值具有隔离性。

      使用类InheritableThreadLocal类可以让子线程中取得父线程中的值,并修改。

      下面使用ThreadLocal来模拟统计五个线程走完一段代码消耗的时间的问题。

      首先创建一个常用的Profiler类

      

    public class Profiler {
    
    	//第一次get()方法调用的时候会进行初始化(前提是set方法未调用),每个线程都会调用一次。
    	private static final ThreadLocal<Long> TIME_THREADLOCAL=new ThreadLocal<Long>(){
    		protected Long initialValue() {
    			return System.currentTimeMillis();
    		};
    	};
    	
    	public static final void begin(){
    		TIME_THREADLOCAL.set(System.currentTimeMillis());
    	}
    	
    	public static final Long end(){
    		return System.currentTimeMillis()-TIME_THREADLOCAL.get();
    	}
    }
    

        主线程中开启五个线程,并调用begin()和end()方法。(关于未调用set直接调用get返回是null的情况,注释已经解释解决办法。也可以通过继承ThreadLocal类,然后重写initialValue()方法改变初始化的值);

      

    public class Run {
    
    	public static void main(String[] args) {
    		
    		for (int i = 0; i < 5; i++) {
    			final int temp=i;
    			Thread thread=new Thread(new Runnable() {
    				@Override
    				public void run() {
    					try {
    						Profiler.begin();
    						Thread.sleep(temp*1000);
    						System.out.println("线程"+Thread.currentThread().getName()+"消耗时间      "+Profiler.end());
    					} catch (Exception e) {
    						e.printStackTrace();
    					}
    					
    				}
    			});
    			thread.start();
    		}
    		
    		
    	}
    }
    

      控制台:

    线程Thread-0消耗时间      0
    线程Thread-1消耗时间      1000
    线程Thread-2消耗时间      2000
    线程Thread-3消耗时间      3001
    线程Thread-4消耗时间      4001
    

      可以发现,五个线程互不影响,各自统计自己的消耗的时间。

      每一个优秀的人,都有一段沉默的时光。不抱怨,不诉苦,最后度过那段感动自己的日子。

      

  • 相关阅读:
    openstack newton 版本 horizon二次开发
    ubuntu 远程root登录
    记录一次用户态踩内存问题
    (leetcode)二叉树的前序遍历-c语言实现
    通过blacklist来禁用驱动
    最小栈问题
    判断是否为环形链表
    按照层次序列创建二叉树,并判断二叉树是否为二叉搜索树
    操作系统交付时需要做哪些安全检查项
    RDMA相关的技术网站
  • 原文地址:https://www.cnblogs.com/hrlizhi/p/9431880.html
Copyright © 2020-2023  润新知