参考:
主要内容:
volatile
ThreadLocal
volatile
volatile
参考:
volatile
关键字用于定义变量,保证变量的 可见性 和 指令重排序
在现代处理器系统中,线程可能会从高速缓存中读取共享变量值,这样有可能会出现高速缓存中的变量值和内存中的变量值不一致
当一个共享变量被 volatile
修饰时,更新后的值会立即保存到内存中,而线程读取该共享变量时,也必须从内存读取
由于 volatile
关键字不能保证 有序性,其适合修饰的共享变量应该仅包含原子操作,比如对 boolean
变量的操作。相对的,如果需要对变量进行加减操作,则不具备原子性
ThreadLocal
ThreadLocal
参考:
ThreadLocal
类可以为线程创建一个共享变量副本,每个线程对该变量的操作均不会影响其它线程
《疯狂Java讲义 16.10 线程相关类》中给出一个示例
定义一个账户类,该类仅包含线程名:
public class Account {
private ThreadLocal<String> name = new ThreadLocal<String>() {
@Override
protected String initialValue() {
// return super.initialValue();
return "Hi zj";
}
};
public Account(String name) {
System.out.println("初始化前:" + this.name.get());
setName(name);
System.out.println("初始化后:" + this.name.get());
}
public String getName() {
return name.get();
}
public void setName(String name) {
this.name.set(name);
}
}
可以在定义 ThreadLocal
对象时调用函数 initialValue
初始化(未初始化的对象值默认为空)
定义一个线程类 MyThread
,使用账户类作为成员变量,并保存其线程名:
public class MyThread extends Thread {
private Account account;
public MyThread(Account account, String name) {
super(name);
this.account = account;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
if (i == 6) {
account.setName(getName());
}
System.out.println(account.getName() + " i = " + i);
}
}
}
测试函数如下:
public static void main(String[] args) {
Account account = new Account("Hello World");
new MyThread(account, "thread-1").start();
new MyThread(account, "thread-2").start();
for (int i = 0; i < 10; i++) {
if (i == 6) {
account.setName(Thread.currentThread().getName());
}
System.out.println(account.getName() + " i = " + i);
}
}
测试函数中共有 3
个线程:main
/ thread-1
/ thread-2
,由结果可知,ThreadLocal
对象各自为这 3
个线程保存了一个副本,它们的修改不会影响对方
其余参考:
为什么说”JAVA中的ThreadLocal是最简单的非阻塞同步”?