代码案例:
public class Counter {
volatile int i = 0;
public void add() {
i++;
}
}
public static void main(String[] args) throws InterruptedException {
final Counter ct = new Counter();
for (int i = 0; i < 6; i++) {
new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 10000; j++) {
ct.add();
}
System.out.println("done...");
}
}).start();
}
Thread.sleep(4000L);
System.out.println(ct.i);
}
测试执行结果是(每次执行结果都不同):
用javap命令编译Counter可得到字节码命令
由上可知:i++这个命令是经过几步完成的,多个线程一起操作会得到不是自己期望的60000值。
可解决办法
- synchronized 方法上加互斥锁
public class Count {
volatile int i= 0;
public synchronized void add(){
i++;
}
}
- 加 Lock 锁
public class Count {
volatile int i= 0;
Lock lock = new ReentrantLock();
public void add(){
lock.lock();
i++;
lock.unlock();
}
}
- 使用AtomicInteger
public class AtomicCount {
AtomicInteger i = new AtomicInteger(0);
public void add(){
i.incrementAndGet();
}
}
查看源码发现AtomicInteger方法 是使用Unsafe类来实现的
自己实现一个由Unsafe方法的使用
public class CountUnsafe {
volatile int i;
private static Unsafe unsafe;
//偏移量
private static long valueOffset;
static {
try {
Field fieldUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
//暴力反射
fieldUnsafe.setAccessible(true);
//静态变量没有参数
unsafe = (Unsafe) fieldUnsafe.get(null);
Field fieldi = CountUnsafe.class.getDeclaredField("i");
//获取偏移量
valueOffset = unsafe.objectFieldOffset(fieldi);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
public void add(){
//this 代表是这个堆里面new的对象
for (;;) {
int current = unsafe.getIntVolatile(this, valueOffset);
//如果成功弹出 不循环了
if(unsafe.compareAndSwapInt(this, valueOffset, current, current + 1)){
break;
}
}
}
}
测试方法
public static void main(String[] args) {
CountUnsafe countUnsafe = new CountUnsafe();
//循环6个线程执行
for (int i = 0; i < 6; i++) {
new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 10000; j++) {
countUnsafe.add();
}
System.out.println("done ...");
}
}).start();
}
//休眠3秒 确定所有线程执行结束
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(countUnsafe.i);
}
测试结果(符合预期):
下面介绍原子操作封装类
实现方法
AtomicIntegerFiledUpdater
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
public class Demo2_AtomicIntegerFieldUpdater {
private static AtomicIntegerFieldUpdater<User> atom =
AtomicIntegerFieldUpdater.newUpdater(User.class,"age");
public static void main(String[] args) {
User user = new User(13, "lisi");
int i = atom.addAndGet(user, 88);
System.out.println(user);
}
}
class User{
volatile int age;
volatile String name;
public User(int age, String name) {
this.age = age;
this.name = name;
}
。。。省略
}
AtomicReference 、 AtomicIntegerArray的使用
public static void main(String args[]) throws InterruptedException {
AtomicIntegerArray array = new AtomicIntegerArray(3);
array.set(1, 14);
array.compareAndSet(1, 14, 13);
AtomicReference<Thread> th = new AtomicReference<>();
Thread thread = th.get();
th.compareAndSet(null, Thread.currentThread());
}
tips:1.8提供了LongAdder 和LongAccumulator的方法来解决
大量线程访问相同的原子值问题 ---分而治之
提高效率、速度差不多
LongAccumulator 用法实例:
import java.util.concurrent.atomic.LongAccumulator;
import java.util.function.LongBinaryOperator;
public class LongAccumulatorDemo {
public static void main(String[] args) {
LongBinaryOperator longBinaryOperator = new LongBinaryOperator() {
@Override
public long applyAsLong(long x, long y) {
System.out.println("x :" + x + " y:" + y);
return x + y;
}
};
LongAccumulator longAccumulator = new LongAccumulator(
longBinaryOperator, 0L);
for (int i = 0; i < 3; i++) {
longAccumulator.accumulate(1);
}
System.out.println("result:" + longAccumulator.get());
//或者直接用lambda写 更方便简洁
LongAccumulator longAccumulator = new LongAccumulator(
(x, y) -> {
System.out.println("x :" + x + " y:" + y);
return x+y;
}, 0L);
}
}
测试 AtomicLong、 LongAdder和LongAccumulator的效率
两秒6个线程可以同时加到多少
public class Demo3_PerformanceTest {
public static void main(String[] args) throws InterruptedException {
Demo3_PerformanceTest demo = new Demo3_PerformanceTest();
long atomicCount = demo.testAtomic();
long adderCount = demo.testLongAdder();
long LongAcc = demo.testAccumulator();
System.out.println("atomicCount:" + atomicCount);
System.out.println("adderCount :" + adderCount);
System.out.println("LongAcc :" + LongAcc);
}
// AtomicLong方式
public long testAtomic() throws InterruptedException {
AtomicLong acount = new AtomicLong(0L);
for (int i = 0; i < 6; i++) {
new Thread(() -> {
long starttime = System.currentTimeMillis();
while (System.currentTimeMillis() - starttime < 2000) { // 运行两秒
acount.incrementAndGet();
}
}).start();
}
Thread.sleep(3000);
return acount.get();
}
// LongAdder 方式
public long testLongAdder() throws InterruptedException {
LongAdder lacount = new LongAdder();
for (int i = 0; i < 6; i++) {
new Thread(() -> {
long starttime = System.currentTimeMillis();
while (System.currentTimeMillis() - starttime < 2000) { // 运行两秒
lacount.increment();
}
}).start();
}
Thread.sleep(3000);
return lacount.sum();
}
public long testAccumulator() throws InterruptedException {
LongAccumulator accumulator = new LongAccumulator((x,y)->{
return x + y;
}, 0L);
for (int i = 0; i < 6; i++) {
new Thread(() -> {
long starttime = System.currentTimeMillis();
while (System.currentTimeMillis() - starttime < 2000) { // 运行两秒
accumulator.accumulate(1);
}
}).start();
}
Thread.sleep(3000);
return accumulator.get();
}
}
得到结果: