public class testDemo implements Runnable{
private volatile int count = 0; // 送出的冰淇淋
@Override
public void run() {
for (int i = 0; i < 100; i++) {
count++;
System.out.println("送出了"+count+"个");
}
}
}
public class test2 {
public static void main(String[] args) {
testDemo demo = new testDemo();
// 开启100个线程
for (int i = 0; i < 100; i++) {
new Thread(demo).start();
}
}
}
启动100个线程,每个线程每次循环送出100个,会出现送出个数不足10000个。
PS:每一个线程每一次执行时都会去内存拷贝一份数据保存到线程栈内存中(副本变量)
当线程1执行到count++时,假设当前共享数据为100,副本变量值拷贝为100,此时count++后值为101,将101赋值给副本变量,此时线程执行权被线程2抢走(线程1还未将副本变量写入内存共享数据),线程1进行睡眠。线程2读取到共享变量(100)执行后写入数据101到共享数据,操作后销毁线程。此时线程1继续执行将数据101写入共享数据。写入两次101数据,导致数据错误。
AtomicInteger类:
空参构造:默认值为0
带参构造:设置默认值
成员方法:
get() 获取值
getAndIncrement() 以原子方式将当前值加一,这里返回的是自增前的值
incrementAndGet() 以原子方式将当前值加一,这里返回的是自增后的值
addAndGet(int data) 以原子方式将参数与对象相加,并返回结果
getAndSet(int value) 以原子方式设置newvalue的值,并返回旧值
public class testDemo implements Runnable{
private volatile int count = 0; // 送出的冰淇淋
AtomicInteger ac = new AtomicInteger(0);
@Override
public void run() {
for (int i = 0; i < 100; i++) {
// count++;
int count = ac.incrementAndGet();
System.out.println("送出了"+count+"个");
}
}
public static void main(String[] args) {
testDemo demo = new testDemo();
// 开启100个线程
for (int i = 0; i < 100; i++) {
new Thread(demo).start();
}
}
}
Atomiclnteger:
自旋锁+cas算法
cas算法:有三个操作数(内存值V,旧的预期值A,要修改的值B)
当旧的预期值A ==内存值,此时修改成功,将V该为B
当旧的预期值A!=内存值,此时修改失败,不做任何操作
并重新获取现在的最新值(这个重新获取的动作就是自旋)
PS:线程1去执行操作,获取假设共享数据值为100,将100赋值给旧值,执行count++,将相加后的101覆盖给变量副本,此时要修改的值为101。 此时线程2执行了同样的操作,共享数据变为101。线程1再次抢回操作全,会拿着旧值去跟共享数据进行判断,如果相等则进行赋值修改,否则再次获取内存中最新的共享数据,重新进行操作