为什么不要在多线程中使用count++

在单线程下,我们经常使用count++将count的值自增1,也不会发生什么错误,但是在多线程下,可能使用count++结果可能就往往出乎我们的意料了.

   
   

我们以count++,一直从1加到5为例

方式一(多个线程操作各自的变量):

public class ThreadCount extends Thread {
    private Integer count = 0;  
    public ThreadCount(String name) {
        this.setName(name);
    }
    
    @Override
    public void run() {
        while (count <5) {
            System.out.println(Thread.currentThread().getName()+":"+count+"--->"+(++count));
        }
    }
    
    public static void main(String[] args) {
        ThreadCount a = new ThreadCount("A");
        ThreadCount b = new ThreadCount("B");
        ThreadCount c = new ThreadCount("C");
        ThreadCount d = new ThreadCount("D");
        ThreadCount e = new ThreadCount("E");
        a.start();
        b.start();
        c.start();
        d.start();
        e.start();
    }
}

 
 

运行结果(多次运行结果不一致,但最终结果都是每个线程的count值变为5):
在这里插入图片描述
内存模型:
在这里插入图片描述
方式一:
我们创建了3个线程,每个线程都有各自的count变量,自己减少自己的count变量的值.这样的情况就是变量不共享,并不存在多个线程访问同一个实例变量的情况.

方式二(多个线程操纵共享变量):

public class ThreadCount1 extends Thread {
    private Integer count = 0;
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+":"+count+"--->"+(++count));
    }
    public static void main(String[] args) {
        ThreadCount1 threadCount1 = new ThreadCount1();
        Thread threadA = new Thread(threadCount1, "A");
        Thread threadB = new Thread(threadCount1, "B");
        Thread threadC = new Thread(threadCount1, "C");
        Thread threadD = new Thread(threadCount1, "D");
        Thread threadE = new Thread(threadCount1, "E");
        threadA.start();
        threadB.start();
        threadC.start();
        threadD.start();
        threadE.start();
    }
}

 
 

运行结果(多次运行结果不一致,count值可能为5可能不为5):
在这里插入图片描述
内存模型:
在这里插入图片描述
方式二:
我们还是新建了5个线程,但是他们是共享主内存中的count变量.我们改变共享变量中的值分为3步:
     ①.从主内存中取出
从运行结果就可以看出,线程B和A同时对count进行了处理,产生了线程安全的问题,使的最终结果变为了4.

注意:虽然System.out.println()是同步的,但是count++操作确实在进入println()之前发生的

 public void println(String x) {
        synchronized (this) {
            print(x);
            newLine();
        }
    }

 
 

方式三(使用锁将count++进行同步):

①使用synchronized进行同步,既能保证一致性又能保证原子性

@Override
    public synchronized void  run() {
        System.out.println(Thread.currentThread().getName() + ":" + count + "--->" + (++count));
    }

 
 

②…其它锁,ReentrantLock

运行结果(每次运行结果相同,count变为5):
在这里插入图片描述
方式三:使用锁进行同步,使的同一时间只有一个线程能够进行访问.(原理以后细讲)

???这里要注意只是用volatile(轻量级锁)只能保证可见性而不能保证count++操作的原子性

private volatile Integer count = 0;

 
 

运行结果(每次运行结果不同,count的值不一定为5)
在这里插入图片描述
可见性:即对于一个volatile的读总能看到(任意线程)对这个volatile变量最后的写入.(原理:内存屏蔽)
原子性:对任意单个volatile变量的读/写具有原子性,但类似于volatile++这种复合操作不具有原子性

count++并不是一个原子操作,它分为3步:
     ①.从内存中取出原有的count值
     ②.进行i++的操作
     ③.把count++后的值赋给count并写入到主内存

方式四(使用Atomic相关类):

private static AtomicInteger count = new AtomicInteger(0);
    @Override
    public void   run() {
        System.out.println(Thread.currentThread().getName() + ":" + count + "--->" + (count.incrementAndGet()));
    }

 
 

运行结果(每次运行结果不相同,count变为5):
在这里插入图片描述
方式四:使用AtomicInteger类并调用incrementAndGet进行count++的操作.(原理:CAS)

方式五(使用java.util.concurrent(juc)下的一些类,如CountDownLatch或者CyclicBarrier等)

因为我对juc下的一些类不太了解,以后深入理解了在来继续写

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Selenium399

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值