ThreadLocal(一)设计ThreadLocal的目的

ThreadLocal(一)设计ThreadLocal的目的
ThreadLoca(二)Looper中ThreadLocal的使用



先看看ThreadLocal类的文档注释:

/**
 * This class provides thread-local variables.  These variables differ from
 * their normal counterparts in that each thread that accesses one (via its
 * {@code get} or {@code set} method) has its own, independently initialized
 * copy of the variable.  {@code ThreadLocal} instances are typically private
 * static fields in classes that wish to associate state with a thread (e.g.,
 * a user ID or Transaction ID).
 *
 * <p>For example, the class below generates unique identifiers local to each
 * thread.
 * A thread's id is assigned the first time it invokes {@code ThreadId.get()}
 * and remains unchanged on subsequent calls.
 * <pre>
 * import java.util.concurrent.atomic.AtomicInteger;
 *
 * public class ThreadId {
 *     // Atomic integer containing the next thread ID to be assigned
 *     private static final AtomicInteger nextId = new AtomicInteger(0);
 *
 *     // Thread local variable containing each thread's ID
 *     private static final ThreadLocal&lt;Integer&gt; threadId =
 *         new ThreadLocal&lt;Integer&gt;() {
 *             &#64;Override protected Integer initialValue() {
 *                 return nextId.getAndIncrement();
 *         }
 *     };
 *
 *     // Returns the current thread's unique ID, assigning it if necessary
 *     public static int get() {
 *         return threadId.get();
 *     }
 * }
 * </pre>
 * <p>Each thread holds an implicit reference to its copy of a thread-local
 * variable as long as the thread is alive and the {@code ThreadLocal}
 * instance is accessible; after a thread goes away, all of its copies of
 * thread-local instances are subject to garbage collection (unless other
 * references to these copies exist).
 *

翻译过来:

此类提供线程本地变量。这些变量不同于线程的普通对应变量,因为访问一个变量的每个线程(通过其get或set方法)都有自己的、独立初始化的变量副本。ThreadLocal实例通常是类中的private static 字段,这个字段希望将状态与线程(例如,用户ID或事务ID)关联的类中。
 例如,下面的类为每个线程生成本地的唯一标识符。
一个线程的id, 在第一次调用时被分配,在随后的调用中保持不变。


 import java.util.concurrent.atomic.AtomicInteger;

 public class ThreadId {
     // Atomic integer containing the next thread ID to be assigned
     private static final AtomicInteger nextId = new AtomicInteger(0);

     // Thread local variable containing each thread's ID
     private static final ThreadLocal<Integer> threadId =
         new ThreadLocal<Integer>() {
             @Override protected Integer initialValue() {
                 return nextId.getAndIncrement();
         }
     };

     // Returns the current thread's unique ID, assigning it if necessary
     public static int get() {
         return threadId.get();
     }
 }
 
 

只要线程处于活动状态且ThreadLocal实例可访问,每个线程都持有对其线程局部变量副本的隐式引用;线程消失后,其线程本地实例的所有副本都将接受垃圾收集(除非存在对这些副本的其他引用)。

java程序中,某个线程的非私有成员变量是可以被其他线程访问和修改的。如下:

public class ThreadTest {
    public static void main(String[] args) {
        ThreadB b = new ThreadB();
        new Thread(new Runnable() {
            @Override
            public void run() {
                b.publicName ="pubThreadBBB";
                b.protectedName = "proThreadBBB";
                b.defaultName = "defThreadBBB";
                System.out.println("将 ThreadB的名字修改为:" + b.defaultName);
            }
        }).start();
    }
}
//新建一个ThreadB.java文件
public class ThreadB extends Thread {
    public String publicName = "ThreadB";
    protected String protectedName = "ThreadB";
    String defaultName = "ThreadB";
    private String privateName = "ThreadB";
}

如果想要某个线程私有的变量,不能被其他线程访问和修改,怎么办?

用private修饰或者设为默认,不就好了。
还真就是这样,我们看看Thread的源码:

public class Thread implements Runnable {
	...
    /* ThreadLocal values pertaining to this thread. This map is maintained
     * by the ThreadLocal class. */
    ThreadLocal.ThreadLocalMap threadLocals = null;
    ...
}

注释翻译过来就是:与此线程相关的ThreadLocal值。此映射由ThreadLocal类维护。所以:
设计ThreadLocal的目的,是为了存储线程私有的变量,其他线程无法访问,也就是实现了线程封闭。

如何防止其他线程,修改线程本地变量?

将ThreadB的写法,修改如下:

public class ThreadB extends Thread {
    //ThreadLocal的注释中,建议用private static修饰
    private static ThreadLocal<String> tl = new ThreadLocal<>(); 

    public ThreadB(String name) {
        super();
        tl.set(name);
    }

    public String getNam() {
        return tl.get(); //ThreadLocal内部有判空处理
    }
}

这样,其他线程,就访问不能修改name变量了。
在这里插入图片描述

如果线程私有的变量有许多,其是不同类型,怎么办?

把多个变量,写在一个类里面,再把这个类作为ThreadLocal的泛型。例如:Android SDK中,Looper内部包含了MessageQueue,MessageQueue就是线程私有的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhangjin1120

可靠的文章费时费力,希望支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值