ThreadLocal:解决多线程安全访问 类静态变量 的问题

JAVA多线程编程中,静态变量是线程非安全的,而ThreadLocal提供了一种解决方案。Android的Looper通过ThreadLocal确保每个线程拥有独立的Looper实例,避免了多线程安全问题。ThreadLocal的使用可以防止多个线程共享同一变量导致的数据冲突。

JAVA 多线程编程 安全结论:

静态变量:线程非安全。

静态变量即类变量,位于方法区,为所有对象共享,共享一份内存,一旦静态变量被修改,其他对象均对修改可见,故线程非安全。

实例变量:单例模式(只有一个对象实例存在)线程非安全,非单例线程安全。

实例变量为对象实例私有,在虚拟机的堆中分配,若在系统中只存在一个此对象的实例,在多线程环境下,“犹如”静态变量那样,被某个线程修改后,其他线程对修改均可见,故线程非安全;如果每个线程执行都是在不同的对象中,那对象与对象之间的实例变量的修改将互不影响,故线程安全。

局部变量:线程安全。

每个线程执行时将会把局部变量放在各自栈帧的工作内存中,线程间不共享,故不存在线程安全问题。



使用ThreadLocal 解决多线程安全访问静态变量的问题:

Android中 Handler 获取消息队列时,不管是主线程还是工作线程都是调用: Looper.myLooper(); 方法,然而 myLooper 方法中确用到了 静态变量sThreadLocal;

按照一般的理解,Java 多线程访问静态变量是线程非安全的,主线程 和工作线程 得到的Looper是同一个looper对象才对,进而得到的是同一个消息队列:mQueue;如果真是这样的话,所有消息都在一个队列里面,岂不是出问题了?!

Android 用ThreadLocal 轻而易举就解决了问题:

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();


静态变量多线程环境中可能会遇到数据可见性和一致性的问题,因为每个线程都直接操作的是同一个静态变量副本。当多个线程同时读写静态变量时,如果不加额外的同步措施,可能导致数据竞争(race condition),如脏读、不可重复读和幻影读现象。 解决多线程静态变量问题通常有以下几个步骤: 1. **加锁**:在访问静态变量前,使用`synchronized`关键字或`ReentrantLock`等同步工具获取锁,确保每次只有一个线程能修改静态变量。 ```java public class Singleton { private static volatile MyObject myObj; public synchronized void operation() { // 操作静态变量 } } ``` 2. **原子操作**:如果变量更新简单,可以考虑使用原子操作(如`AtomicInteger`、`AtomicReference`等)来避免上下文切换带来的同步开销。 3. **使用`ThreadLocal`**:如果多个线程都需要独立的数据副本,可以考虑使用`ThreadLocal`,它为每个线程创建独立的局部变量副本。 4. **避免不必要的全局状态**:尽量减少全局静态变量的使用,它们往往是引发并发问题的根源。若可能,倾向于将状态封装到单例模式的对象或其他适当的设计模式中。 5. **定期刷新或初始化**:某些场景下,可以在初始化静态变量时就设置好初始值,或者在多线程环境下只允许单线程进行初始化。 记住,尽管静态变量本身不会导致死锁,但如果在一个复杂的同步结构中,滥用静态变量仍然可能导致难以调试的并发问题。因此,良好的并发设计原则至关重要。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值