一、ThreadLocal
线程绑定,辅助一个线程持有自己的数据,这个数据与其他线程不共享。把数据绑定到线程,线程当做一条流水线,来传递数据。多线程并行时,数据是安全的。
例:
public class Test {
static ThreadLocal<Double> threadLocal = new ThreadLocal<>();
public static void main(String[] args) {
new Thread() {
@Override
public void run() {
a();
b();
c();
removeData();
}
}.start();
new Thread() {
@Override
public void run() {
a();
b();
c();
removeData();
}
}.start();
new Thread() {
@Override
public void run() {
a();
b();
c();
removeData();
}
}.start();
}
static void a() {
double d = getData();
String n = Thread.currentThread().getName();
System.out.println(n+" - "+d);
}
static void b() {
double d = getData();
String n = Thread.currentThread().getName();
System.out.println(n+" - "+d);
}
static void c() {
double d = getData();
String n = Thread.currentThread().getName();
System.out.println(n+" - "+d);
}
static double getData() {
Double d = threadLocal.get();//从当前线程获取绑定的数据
if (d == null) {//如果线程上没有绑定过数据
//产生一个数据,绑定到当前线程
d = Math.random();
threadLocal.set(d);
}
return d;
}
static void removeData() {
threadLocal.remove();
}
}
二、 volatile
- 共享变量的可见性
- 禁止指令重排的优化
cpu 为了提高运算效率,可能根据一定规则,对运算指令重新排序
a = 6; flag = true
flag = true; a = 6;
- 不能包装原子性, 只能靠锁来解决
- 什么时候使用volatile
- volatile 易变,不稳定
- 多个线程频繁访问,修改变量
例:
public class Test {
/*
* volatile 保证数据的可见性
*
* volatile 涉及一些底层cpu指令
* 可以让一个cpu缓存,监视其他cpu的数据变化,
* 发现其他cpu修改了数据,会把高速缓存数据标记成废弃,
* 会重新从内存复制新数据
*/
public static volatile boolean flag = false;//共享的变量
public static void main(String[] args) throws InterruptedException {
T1 t1 = new T1();
T2 t2 = new T2();
new Thread(t1, "T1").start();
Thread.sleep(1000);//为了保证t1比t2先启动,sleep一下
new Thread(t2, "T2").start();
}
static class T1 extends Thread {
public void run() {
while (true) {
if (flag) {
System.out.println(Thread.currentThread().getName() + " - flag : " + flag);
break;
}
}
}
}
static class T2 extends Thread {
public void run() {
flag = true;
System.out.println(Thread.currentThread().getName() + " - flag : " + flag);
}
}
}