ThreadLocal

目录

场景:

结果:

​编辑分析:

ThreadLocal

作用:

理解:

修改上述代码 :

结果: 

分析:

观察ThreadLocal类的set()方法

总结:

作用一传递数据:

ThreadLocal类中方法:

set(T val)

  createMap(Thread t, T firstValue)

 理解:

T get()

getEntry(ThreadLocal key)

Synchroized是Java内建的同步机制,它提供了互斥的语义和可见性,

当一个线程已经获取锁时,其他视图获取的线程只能阻塞在那里。

在加锁和解锁的过程中:

1、依赖于操作系统互斥锁【Mutex Lock】所实现的锁,消耗资源,属于重量级锁。

2、在Java1.6以前,另外在获取锁时,必须一直处于等待,没有额外的尝试机制

场景:

定义一个公共变量,在各自的线程中保存一个role角色,并取出role,

期望结果:各自拿到各自的role角色

阅读以下代码

public class Demo03 {
    
    public static String role = "";
    public static void show () {
        String role = "";
        System.out.println("show: "+Thread.currentThread().getName()+"分配角色:"+role);
    }

    public static void main(String[] args) {
        
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
              role  = "线程2中的角色-莫琪临";
              show();
              Sample.dosth();

            }
        }, "线程1");

        
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                role  = "线程1中的角色-顾倾城";
                show();
                Sample.dosth();
            }
        }, "线程2");    
        t1.start();
        t2.start();    
    }
}

class Sample{
    public static void dosth () {
        String role = Demo03.role;
        System.out.println("dosth:"+Thread.currentThread().getName()+"分配角色:"+role);
    }
}

结果:

分析:

    公共变量的存储,后一个线程会覆盖公共变量值,导致最终结果达不到预期目标

    想达到预期结果,需要使用ThreadLocal存储

ThreadLocal

作用:

    每个线程自己独有的数据存储,仅供当前线程访问

理解:

   数据是存储在该线程里的,只针对当前线程,属于当前线程局部的数据

修改上述代码 :

public static ThreadLocal<String> threadLocal = new ThreadLocal<String>();

都是通过threadLocal 来访问

set("名称")                 ------存储

get()                           -------取

public class Demo01 {
	
	public static ThreadLocal<String> threadLocal = new ThreadLocal<String>();
	
	public static void main(String[] args) {
		Thread t1 = new Thread(new Runnable() {

			@Override
			public void run() {
		      threadLocal.set("妲己");
		      show();
		      Sample.dosth();

			}
		}, "线程1");

		t1.start();
		Thread t2 = new Thread(new Runnable() {

			@Override
			public void run() {
				 threadLocal.set("后羿");
			      show();
			      Sample.dosth();

			}
		}, "线程2");
		t2.start();
		
	}
	
	public static void show () {
		String role  = threadLocal.get();
		System.out.println("show: "+Thread.currentThread().getName()+"分配角色:"+role);
	}

}

class Sample{
	public static void dosth () {
		String role = Demo01.threadLocal.get();
		System.out.println("dosth:"+Thread.currentThread().getName()+"分配角色:"+role);
	}
}

结果: 

分析:

观察ThreadLocal类的set()方法

   先获取当前线程

   在获取当前线程的ThreadLocalMap:当前线程内部存储的键值对集合,在ThreadLocal中定义类型,在Thread类中应用。

   所以ThreadLocal存储就是在该线程对象中,不能直接访问,通过ThreadLocal取

可以这样理解:每个线程的内部都有一个键值对集合

总结:

作用一传递数据:

需要在不同线程中共享数据,将数据存储到Thread对象里【在每个Thread对象里都有ThreadLocalMap】,通过ThreadLocal来访问该数据【理解为中介】

ThreadLocal类中方法:

set(T val)

    public void set(T value) {
      //那个线程执行,就获取那个线程
        Thread t = Thread.currentThread();
     //得到ThreadLocalMap
        ThreadLocalMap map = getMap(t);
    
        if (map != null) {
            map.set(this, value);//以键值对的形式存储
        } else {
            createMap(t, value);//由于该map只是在Thread里面声明,所以第一次访问的时候需要创建
        }
    }

  createMap(Thread t, T firstValue)

//传Thread t 是为了拿到threadLcoals的引用 
void createMap(Thread t, T firstValue) {
      //接受两个参数,实例化
      //this ---Threalocal调用this就是该ThreadLocal
      //val  ---值
      t.threadLocals = new ThreadLocalMap(this, firstValue);
 }

 理解:

线程Thread对象,以参数t为例:

     t 的内部有一个ThreadLocalMap,该Map的引用名叫做ThreadLocals,在定义时指向null,

     现在需要将它new出来,进行实例化。

     该方法传进来的是 t 线程,就完成 t 线程中ThreadLocalMap的创建

     ThreadLocalMap的构造方法中传递两个值【和HashMap很像】:

一个线程里面可以有多个ThreadLocal,ThreadLocal自己充当这个Key【谁存谁来作键】,

    【理解】用银行卡存钱,用该卡取钱

ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
  //完成数组的初始化INITIAL_CAPACITY=16
    table = new Entry[INITIAL_CAPACITY];
 //计算下标
    int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
 //键值对存储 --
    table[i] = new Entry(firstKey, firstValue);
    size = 1;
    setThreshold(INITIAL_CAPACITY);
}

T get()

public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
      //getEntry()---根据当前键得到当前键值对
        //键是不同的ThreadLocal,
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}

getEntry(ThreadLocal<?> key)

private Entry getEntry(ThreadLocal<?> key) {
    //计算下标
    int i = key.threadLocalHashCode & (table.length - 1);
    Entry e = table[i];//得到Entry键值对
    if (e != null && e.get() == key)
        return e;
    else
        return getEntryAfterMiss(key, i, e);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值