静态变量的线程安全

发布于 2024-12-04 18:52:17 字数 316 浏览 0 评论 0原文

class ABC implements Runnable {
    private static int a;
    private static int b;
    public void run() {
    }
}

我有一个如上所述的 Java 类。我有这个类的多个线程。在 run() 方法中,变量 a & b 分别递增多次。在每个增量中,我将这些变量放入哈希表中。

因此,每个线程都会增加这两个变量并将它们放入哈希表中。如何使这些操作线程安全?

class ABC implements Runnable {
    private static int a;
    private static int b;
    public void run() {
    }
}

I have a Java class as above. I have multiple threads of this class. In the run() method, the variables a & b are incremented each for several times. On each increment, I am putting these variables in a Hashtable.

Hence, each thread will increment both variables and putting them in Hashtable. How can I make these operations thread safe?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

〃安静 2024-12-11 18:52:17

我会使用 AtomicInteger,它被设计为线程安全的,并且非常易于使用,并且为应用程序带来绝对最小的同步开销:

class ABC implements Runnable {
    private static AtomicInteger a;
    private static AtomicInteger b;
    public void run() {
        // effectively a++, but no need for explicit synchronization!
        a.incrementAndGet(); 
    }
}

// In some other thread:

int i = ABC.a.intValue(); // thread-safe without explicit synchronization

I would use AtomicInteger, which is designed to be thread-safe and is dead easy to use and imparts the absolute minimal of synchronization overhead to the application:

class ABC implements Runnable {
    private static AtomicInteger a;
    private static AtomicInteger b;
    public void run() {
        // effectively a++, but no need for explicit synchronization!
        a.incrementAndGet(); 
    }
}

// In some other thread:

int i = ABC.a.intValue(); // thread-safe without explicit synchronization
听不够的曲调 2024-12-11 18:52:17

取决于什么需要线程安全。对于这些 int 原语,您需要将它们替换为 AtomicInteger 的原语,或者仅在 synchronized 方法或块中使用它们。如果您需要使跨线程 Hashtable 线程安全,则无需执行任何操作,因为它已经同步了。

Depends on what needs to be thread-safe. For these int primitives, you'll need either to replace them with AtomicInteger's or only operate with them within synchronized method or block. If you need to make your cross-thread Hashtable thread-safe, you don't need to do anything, as it already is synchronized.

清君侧 2024-12-11 18:52:17

使用 synchronized 方法,例如

public synchronized void increment()
{
  a++; b++;
  // push in to hash table.
}

,如果您通过单个实例访问静态数据,上面的方法很好,但是如果您有多个实例,那么您需要在某些静态对象上进行同步 - 类似(未经测试) ..

private static Object lock = new Object();

在方法中

public void increment()
{
  synchronize(lock)
  {
    a++;b++;
    // do stuff
  }
}

注意:这些方法假设您希望在一个原子操作中递增ab,其他答案强调了它们如何可以单独使用原子递增。

Use a synchronized method, e.g.

public synchronized void increment()
{
  a++; b++;
  // push in to hash table.
}

The above is good if you are accessing the statics through a single instance, however if you have multiple instances, then you need to synchronize on some static object - something like (untested)..

private static Object lock = new Object();

in the method

public void increment()
{
  synchronize(lock)
  {
    a++;b++;
    // do stuff
  }
}

NOTE: These approaches assume that you want to increment a and b in one atomic action, the other answers highlight how they can be individually incremented using atomics.

烟织青萝梦 2024-12-11 18:52:17

我想添加一些关于这个问题的答案的细节。

首先,OP 询问的是:

如何使这些操作线程安全?

在回答这个问题之前,我们需要对什么是线程安全达成一致。我最喜欢的定义来自“Java Concurrency In Practice”,它是

如果类在访问时行为正确,则该类是线程安全的
来自多个线程,无论调度或
运行时交错执行这些线程
环境,并且没有额外的同步或其他
调用代码部分的协调。

如果您同意这个定义,则意味着我们在进一步讨论之前达成了一致。让我们回到你所说的操作,它是a++b++,增量之后,你将把它们放入一个HashTable中。

对于a++操作来说,它并不是真正的单一操作。它遵循读修改写模型。正如您所看到的,它实际上包含三个单独的步骤。读取该值,将其加一并保存回来。如果有两个线程同时读取值为1的变量a,则在修改和保存回操作之后。该值将为 2,但实际上应该为 3。为了避免这种情况发生,就像其他人建议的那样,您可以直接使用 AtomicInteger 而不是 int 类型。 AtomicInteger 将保证一些操作(例如增量)以原子方式执行。这意味着读取修改写入操作不能被分割,并且将作为一个单独的步骤执行。
之后,OP 想要将值保存到哈希表中。 HashTable 是一个线程安全的容器,不需要其他同步。
希望这个澄清可以以其他方式帮助别人。谢谢。

I'd like to add some details about the answer to this question.

Firstly, the OP is asking about :

How can I make these operations thread safe?

Before answer this question, we need to reach the consistency about what is thread safe. The definition I like mostly is that from "Java Concurrency In Practice" and it's

A class is thread safe if it behaves correctly when accessed
from multiple threads, regardless of the scheduling or
interleaving of the execution of those threads by the runtime
environment, and with no additional synchronization or other
coordination on the part of the calling code.

If you agree with the definition, it means we reach the consistency before further discussion. Let's return to the operations you meant, it's a++ and b++, after the increment, you will put them into a HashTable.

For the a++ operation, it's not really a single operation. It obeys the model of read modify write. As you can see, it actually contains three individual steps. Read the value, add one to it and save it back. If you have two threads read the variable a with value 1 at the same time, after the modifications and save back operations. The value will be 2, but it actually should be 3. To avoid this situation happen, like what others have suggested, you can use AtomicInteger instead of int type directly. The AtomicInteger will guarantee some operations like increment to execute atomically. That means, the read modify write operations can't be divided and will be executed as one individual step.
After that, the OP wants to save the value into a HashTable. The HashTable is a thread safe container, no other synchronization needed.
Hope this clarification can help someone in other way. Thanks.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文