为了保证多线程的三个特性,Java引入了很多线程控制机制,这里主要介绍几种
机制 | 作用 |
---|---|
ThreadLocal | 线程本地变量,提供局部变量为每个线程保存一份副本 |
原子类 | 保证变量的原子性 |
lock类 | 保证线程有序性 |
Volatile | 保证线程变量可见性 |
一.ThreadLocal
1.1作用
提供线程局部变量,为使用相同变量的每一个线程维护一个该变量的副本。使用的场景是:当某些数据是以线程为作用域并且不同线程有不同数据副本的时候,可以采用ThreadLocal,
1.2 常用方法
方法 | 作用 |
---|---|
initValue() | 副本创建的方法 |
get() | 获取副本的方法 |
set() | 设置副本的方法 |
1.3示例:两个线程转账
public class ThreadLocalDemo {
//银行对象,有钱,有存款和取款两个操作
static class Bank{
ThreadLocal<Float> threadLocal = new ThreadLocal<Float>() {
protected Float initialValue() {
return 0.0f;
}
};
//存款
public Float get() {
return threadLocal.get();
}
//取款
public void set(Float money) {
threadLocal.set(threadLocal.get()+money);
}
}
//转账对象,从银行中取钱然后转账,然后保存到账户
static class Transfer implements Runnable{
private Bank bank;
public Transfer(Bank bank){
this.bank = bank;
}
@Override
public void run() {
// TODO Auto-generated method stub
for(int i = 0;i<10;i++) {
bank.set(10.0f);
System.out.println(Thread.currentThread().getName()+"账户余额"+bank.get());
}
}
}
}
在main中模拟转账
Bank bank = new Bank();
Transfer transfer = new Transfer(bank);
Thread t1 =new Thread(transfer,"客户1");
Thread t2 =new Thread(transfer,"客户2");
t1.start();
t2.start();
执行结果:
1.4分析
ThreadLocal能实现为不同的线程保存变量的原理是,它内部有个Entry,保存<线程名,变量值>,不同的线程对应着不同的value,就能加以区分了
二.原子类
Java在java.util.concurrent.atomic包中提供了很多进行原子操作的类,分为以下四大类:
操作 | 类型 |
---|---|
原子更新基本类型 | AtomicInteger,AtomicBoolean,AtomicLong |
原子更新数组类型 | AtomicIntegerArray,AtomicLongArray |
原子更新引用类型 | AtomicReference,AtomicStampedReference |
原子更新属性类型 | AtomicIntegerFileUpdater,AtomicLongFileUpdater |
这些类的提供目的在于为了解决基本类型的非原子性导致在多线程并发情况下引发的问题
2.1非原子性操作问题演示
例如:i++并不是原子操作,有三个操作组成
- tp1 = i;
- tp2 = tp1+1;
- tp1 = tp2;
单线程下这个代码不会有问题,但在多线程下会出现问题
static private int n;
public static void main(String[] args) throws InterruptedException {
int j = 0;
while(j<100) {
n=0;
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<1000;i++) {
n++;
}
}
});
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<1000;i++) {
n++;
}
}
});
t1.start();
t2