如何使这个简单而不是线程安全的计数器类线程安全?

时间:2017-10-28 05:24:08

标签: java multithreading thread-safety

这是一个简单的非线程安全的Counter类,我想让线程安全。

public class Counter{
private static int val = 0;

public Counter() {
}

public static void set(int newVal) {
    val = newVal;
}

public static void decrement() {
    int tmp = val;

    try {
        Thread.sleep(100L);
    } catch (Exception var2) {
        ;
    }

    --tmp;
    val = tmp;
}

public static boolean depleted() {
    return val == 0;
}

}

我知道synchronised方式,并已在下面实施:

public static synchronised void decrement() {
    val--
}

现在我试图弄清楚任何其他简单的方法来使类线程安全吗?

特别是我正在查看java库java.util.concurrentatomic data structures。我将如何实施这些?即使是对它们的解释,也像伪代码一样,将不胜感激。

谢谢

编辑:为什么选票?我想学习:(

2 个答案:

答案 0 :(得分:0)

简单的方法是:

  • 制作Counter synchronized
  • 的所有方法
  • 使Counter类成为AtomicInteger实例的包装器。
  • 只需使用AtomicInteger

值得注意的是,这是个坏主意:

try {
    Thread.sleep(100L);
} catch (Exception var2) {
    ;
}

正确实施的计数器不应随意延迟通话。它不属于"规范" (即预期行为)柜台。

如果sleep(100L)调用的目的是(以某种方式)帮助您证明您的计数器代码是线程安全的,那么它就赢了:

  • 通过运行代码并查看代码是什么来证明代码是线程安全的 这种方法只会给你无效的证明"以及对你的代码正在做什么的错误认识。

  • 由于Thread.sleep(...)调用的某些未指定的同步效果,它实际上可能导致偶然的同步。添加sleep(或打印或日志语句)可能会更改行为多线程代码。 (就像使用调试器运行它一样。)

另外,抓住Exception坏主意。捕获您期望的特定异常。捕捉"一切"可以使您捕获实际上代码中的错误证据。 (一般情况下,如果不在这里。)这样做是一个糟糕的编码习惯,很可能会在将来的某个时候伤害你。

答案 1 :(得分:0)

使用AtomicInteger代替整数来跟踪coints。 它提供了诸如decrementAndGetgetAndSet(int newValue)等原子方法。