线程之间的共享变量可以通过public static变量的形式实现,如果要实现每一个线程都有自己私有的变量,最简单的方法就是为每一个启动的线程初始化一个线程实例
一个线程对应一个线程实例,如以下代码所示:
class MyThread extends Thread{
public String test;
MyThread(String val){
this.test=val;
}
@Override
public void run(){
System.out.println("线程——"+Thread.currentThread().getName()+"变量arg的值是:"+test);
}
public static void main(String[] args) {
new MyThread("A").start();
new MyThread("B").start();
new MyThread("C").start();
}
}
输出结果:
线程——Thread-0变量test的值是:A
线程——Thread-2变量test的值是:C
线程——Thread-1变量test的值是:B
比一个线程创建一个线程实例更灵活的方法就是使用ThreadLocal类,实现线程之间的变量隔离。
ThreadLocal类的使用如以下代码所示:
class MyThreadLocalTest extends Thread{
public static ThreadLocal<String>local=new ThreadLocal<>();
@Override
public void run(){
local.set(Thread.currentThread().getName());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程——"+Thread.currentThread().getName()+"变量local的值是:"+local.get());
}
public static void main(String[] args) {
MyThreadLocalTest test=new MyThreadLocalTest();
new Thread(test,"A").start();
new Thread(test,"B").start();
new Thread(test,"C").start();
}
}
输出结果:
线程——C变量local的值是:C
线程——B变量local的值是:B
线程——A变量local的值是:A
虽然A、B、C三个线程使用的是同一个线程实例,并且对变量local都进行了赋值,但输出的结果表示三个线程的local变量的值各不相同,并没有发生值覆盖,所以三个线程的local变量是相互隔离的,不是共享变量。也就是说ThreadLocal类实现了线程之间的变量隔离。
那么ThreadLocal类对于线程之间变量隔离的实现原理是什么呢?
每个Thread实例中都会有一个ThreadLocalMap对象threadLocals,其中存储的是键值对,键值对的存储格式为为“ThreadLocal实例 —> Value”。
当调用ThreadLocal变量local的set方法时,方法内部会通过Thread.currentThread获取当前线程,再从当前线程中获取ThreadLocalMap,往ThreadLocalMap中存储键值,健就是当前的ThreadLocal变量local,值就是set(val)的参数val。
当我们要获取ThreadLocal变量对所对应的值时,同理,获取到当前线程的ThreadLocalMap对象,在该map中获取ThreadLocal变量local对应的value即可。这就是ThreadLocal中get方法的原理。
ThreadLocal存储结构如下图所示: