当前位置: 首页 > 面试题库 >

多线程环境中的增量和减量

冀嘉木
2023-03-14
问题内容

我正在尝试在多线程环境中对int变量进行经典的递增/递减。这是我的示例代码。

public class SyncIncDec {


    public static void main(String[] args) {

        SyncCounter count = new SyncCounter();

        Thread incThread = new Thread(() -> {
            count.increment();
        });

        Thread decThread = new Thread(() -> {
            count.decrement();
        });

        Thread displayThread = new Thread(() -> {
            System.out.println("Count value : " + count.getX());
        });

        incThread.start();
        decThread.start();
        displayThread.start();

        try {
            incThread.join();
        } catch (InterruptedException e) {
//          e.printStackTrace();
        }

        try {
            decThread.join();
        } catch (InterruptedException e) {
//          e.printStackTrace();
        }

        try {
            displayThread.join();
        } catch (InterruptedException e) {
//          e.printStackTrace();
        }

    }

}


class SyncCounter {

    private int x=0;

    public SyncCounter() {
        super();
    }

    public SyncCounter(int y) {
        super();
        x = y ;
    }

    synchronized int  getX() {
        return x; 
    }

    void setX(int y) {
        x = y ;
    }

    void increment() {
        ++x;
    }


    void decrement() {
        --x;
    }

}

尽管我对所有三个线程都使用了join()方法,但结果仍然不一致。在这里加入不是意味着主线程要等到每个线程都完成执行吗?我什至尝试将同步添加到三个方法签名中的每个;但是我得到不一致的结果。

除了使用该变量的Atomic版本外,我还能如何确保始终获得0?


问题答案:

您的SyncCounter根本不是线程安全的。可变方法的增量和减量应同步。现在,实现此类的正确方法是原子式的。例如:

class SyncCounter {

    private final AtomicInteger x;

    public SyncCounter() {
     this(0);   
    }

    public SyncCounter(int x) {
       this.x = new AtomicInteger(x);
    }

    int getX() {
        return x.get(); 
    }

    void setX(int x) {
        this.x.set(x);
    }

    int increment() {
        return x.incrementAndGet();
    }


    int decrement() {
        return x.decrementAndGet();
    }

}

和测试代码:

    final Thread incThread = new Thread(() -> {
        count.increment();
    });

    final Thread decThread = new Thread(() -> {
        count.decrement();
    });

    Thread displayThread = new Thread(() -> {
        incThread.join();
        decThread.join();
        System.out.println("Count value : " + count.getX());
    });


 类似资料:
  • 我目前正在学习多线程,我发现了一些我无法解释的有趣的东西。据我所知,如果两个线程访问一个静态变量,它们可以将自己的副本复制到缓存中。Thread1对其本地缓存中的静态变量进行的更新不会反映在Thread2缓存的静态变量中。 java java

  • 我有几个问题。 > 如果我连续调用getSomeData(),是否每次都为stmt和rs分配新对象? 不管上面问题的答案如何,如果我在多线程环境中运行这段代码(使用MysqlUtils类的多线程),会不会因为我没有在getSomeData()中声明ResultSet rs而出现混淆?

  • 我的 Web 应用程序中出现随机错误,我迷路了。我创建了一个库来解码代码。我尝试了很多,从未失败过测试。但突然间,它开始随机失败。由于它在单线程测试中运行良好,有时在 servlet 环境中失败时,我能想象的唯一解释是问题与多线程环境中使用的库有关。老实说,我知道多线程是一个非常复杂的问题。我担心我的库可能不是线程安全的。顺便说一下,它非常简单,它是一个具有几种静态方法的正面类。基本上,假设您正在

  • 我在学习多线程时发现对象的速度变慢了。hashCode在多线程环境中,因为对于相同数量的对象,计算运行4个线程的默认哈希代码要比运行1个线程的默认哈希代码花费两倍的时间。 但根据我的理解,并行完成这项工作也需要类似的时间。 您可以更改线程数。每个线程都有相同的工作量,因此您希望在我的四核机器上运行4个线程可能需要与运行单个线程相同的时间。 我看到4x大约2.3秒,但是。1x为9秒。 我的理解是否有

  • 现在,他提出的下一个问题是为多线程环境编写单例类。然后,我写了双重检查单例类。 然后,他反对使用和双重检查,并说这是没用的。为什么要检查两次,为什么要使用synchronized?我试着用多种方案说服他。但是,他没有。 后来,我在家里尝试了下面的代码,在那里我使用了带有多个线程的简单的单例类。 那么,问题是,在多线程环境中是否有必要使用或/和双重检查方法?似乎我的第一个代码本身(没有添加任何额外的

  • 如果我有多个线程,每个线程使用injector获取EntityManager对象,每个线程使用em对象选择其他类对象的列表。准备好在for循环中使用。 如果一个线程首先完成并调用clear(),这会影响其他线程吗?比如for循环会有异常? 谢谢你。