多线程下实现自增的几种方式
发布日期:2021-04-30 21:03:10 浏览次数:103 分类:精选文章

本文共 5363 字,大约阅读时间需要 17 分钟。

多线程环境下i++操作的实现问题

在多线程环境下,直接使用i++操作可能会引发严重的竞态条件,导致无法达到预期的效果。以下将从多个角度分析这一问题,并探讨解决方案。

直接自增操作的错误

首先,我们来看直接使用i++的多线程实现方式。以下代码片段展示了一个简单的多线程程序:

public class byte1 extends Thread {    static int a = 0;    @Override    public void run() {        for (int i = 1; i <= 10000; i++) {            a++;        }    }    public static void main(String[] args) {        long nowTimeMillis = System.currentTimeMillis();        byte1 tByte1 = new byte1();        List
threads = new ArrayList<>(); for (int i = 1; i <= 10; i++) { threads.add(new Thread(tByte1)); } for (Thread thread : threads) { thread.start(); } for (Thread thread : threads) { try { thread.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println(a); long nowTimeMillis1 = System.currentTimeMillis(); System.out.println(nowTimeMillis1 - nowTimeMillis + "ms"); }}

运行结果显示,多线程直接自增操作无法正确增加到100000,结果差距很大。这是因为i++操作并非原子操作,容易在多线程环境下出现竞态条件。

volatile的可见性不足

接下来,我们尝试通过volatile来解决这个问题。以下是修改后的代码:

public class byte1 extends Thread {    volatile static int a = 0;    @Override    public void run() {        for (int i = 1; i <= 10000; i++) {            a++;        }    }    public static void main(String[] args) {        long nowTimeMillis = System.currentTimeMillis();        byte1 tByte1 = new byte1();        List
threads = new ArrayList<>(); for (int i = 1; i <= 10; i++) { threads.add(new Thread(tByte1)); } for (Thread thread : threads) { thread.start(); } for (Thread thread : threads) { try { thread.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println(a); long nowTimeMillis1 = System.currentTimeMillis(); System.out.println(nowTimeMillis1 - nowTimeMillis + "ms"); }}

尽管使用了volatile关键字,结果仍然无法达到预期。这是因为volatile只能保证可见性和指令不重排,但无法保证原子性。例如,当一个线程读取a的值时,另一个线程可能已经修改了a,这会导致读取到的值不正确。

正确的实现方案

为了确保i++操作的原子性,我们可以采用以下方法:

  • 使用synchronized加锁
  • 通过对代码块加锁,可以确保在多线程环境下操作的原子性。以下是修改后的代码:

    public class byte1 extends Thread {    static int a = 0;    @Override    public void run() {        synchronized (this) {            for (int i = 1; i <= 10000; i++) {                a++;            }        }    }    public static void main(String[] args) {        long nowTimeMillis = System.currentTimeMillis();        byte1 tByte1 = new byte1();        List
    threads = new ArrayList<>(); for (int i = 1; i <= 10; i++) { threads.add(new Thread(tByte1)); } for (Thread thread : threads) { thread.start(); } for (Thread thread : threads) { try { thread.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println(a); long nowTimeMillis1 = System.currentTimeMillis(); System.out.println(nowTimeMillis1 - nowTimeMillis + "ms"); }}
    1. 使用AtomicInteger
    2. AtomicInteger提供了一个线程安全的原子性增量操作。以下是修改后的代码:

      public class byte1 extends Thread {    static AtomicInteger a = new AtomicInteger(0);    @Override    public void run() {        for (int i = 1; i <= 10000; i++) {            a.incrementAndGet();        }    }    public static void main(String[] args) {        long nowTimeMillis = System.currentTimeMillis();        byte1 tByte1 = new byte1();        List
      threads = new ArrayList<>(); for (int i = 1; i <= 10; i++) { threads.add(new Thread(tByte1)); } for (Thread thread : threads) { thread.start(); } for (Thread thread : threads) { try { thread.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println(a.get()); long nowTimeMillis1 = System.currentTimeMillis(); System.out.println(nowTimeMillis1 - nowTimeMillis + "ms"); }}
      1. 使用LongAdder
      2. LongAdder提供了一个线程安全的原子性加法操作。以下是修改后的代码:

        public class byte1 extends Thread {    static LongAdder a = new LongAdder();    @Override    public void run() {        for (int i = 1; i <= 10000; i++) {            a.increment();        }    }    public static void main(String[] args) {        long nowTimeMillis = System.currentTimeMillis();        byte1 tByte1 = new byte1();        List
        threads = new ArrayList<>(); for (int i = 1; i <= 10; i++) { threads.add(new Thread(tByte1)); } for (Thread thread : threads) { thread.start(); } for (Thread thread : threads) { try { thread.join(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } System.out.println(a); long nowTimeMillis1 = System.currentTimeMillis(); System.out.println(nowTimeMillis1 - nowTimeMillis + "ms"); }}

        通过以上方法,我们可以确保在多线程环境下正确实现i++操作,避免竞态条件带来的问题。选择哪种方法取决于具体的需求和性能考虑。

    上一篇:线程-线程概念(一)
    下一篇:剑指offer打卡Day18 栈的压入、弹出序列(重新学习 Vector 与 Stack)

    发表评论

    最新留言

    路过按个爪印,很不错,赞一个!
    [***.219.124.196]2026年06月07日 19时12分14秒