简体   繁体   English

没有任何参数的静态方法是线程安全的吗?

[英]Is static method without any parameters thread-safe?

I have a counter and multiple threads access the getCount method. 我有一个计数器,并且有多个线程访问getCount方法。 The code is like the following: 代码如下:

public class ThreadSafeMethod {

        public static int counter = 0;

        public static int getCount() {
            return counter++;
        }
    }

Is the method thread safe? 方法线程安全吗? My understanding is that because counter++ is not atomatic, it is not safe. 我的理解是,因为counter++不是原子的,所以它并不安全。 Then how to make it safe? 那么如何使其安全呢? If we add synchronized keyword, what object will be synchronized? 如果我们添加synchronized关键字,将同步哪个对象?

You are correct in your analysis when you say that it's not thread safe because the operation is not atomic. 当您说它不是线程安全的,因为该操作不是原子的,因此您的分析是正确的。 The retrieval of the value and the increment are not thread safe. 值和增量的检索不是线程安全的。 Multiple calls to this method (whether it has parameters or not) access the same non-local variable. 对该方法的多次调用(无论是否具有参数)都访问相同的非局部变量。

Adding synchronized to this method makes it thread-safe. synchronized添加到此方法使其具有线程安全性。 When adding to a static method, then the Class object is the object which is locked. 当添加到static方法时, Class对象就是被锁定的对象。

An alternative to making it thread-safe is to replace the int with an AtomicInteger , which has its own atomic getAndIncrement method. 使它成为线程安全的另一种方法是用AtomicInteger替换int ,该AtomicInteger具有自己的原子getAndIncrement方法。

No , a parameter-less method is not inherently thread-safe - the lack of parameters makes no difference in this example. ,无参数方法本身并不是线程安全的-在此示例中,缺少参数没有区别。

The read from (and write to) the counter variable is not guaranteed to be either atomic or consistent between threads. 不能保证对counter变量的读取(和写入)是原子的或线程之间的一致性

The simplest change is to simply make the method synchronized : 最简单的更改是使方法synchronized

public static synchronized int getCount() {
    return counter++;
}

(The simplest is not always the "best" or "correct", but it will be sufficient here, assuming that no other code touches the public counter variable.) (最简单的方法并不总是“最佳”或“正确”,但在这里,只要没有其他代码触及公共counter变量,就足够了。)

See this answer for how a synchronization of a static method works - as can be imagined, it is the Class itself that is used as the monitor. 请参见此答案以了解静态方法的同步如何工作-可以想象,是类本身用作监视器。

Using the synchronised keyword on the static function will 'lock' the function to one thread at a time to ensure that two threads can not mess with the same variable. 在静态函数上使用synced关键字将使函数一次“锁定”到一个线程,以确保两个线程不会混淆同一个变量。 With what you propose, I believe anything that gets accessed or modified in that function will be thread safe. 根据您的建议,我相信在该函数中访问或修改的所有内容都是线程安全的。

Just as you say the counter++ operation is non atomic so giving multiple threads access at once will result in undefined behaviour. 就像您说counter++操作是非原子的一样,因此一次给多个线程访问将导致不确定的行为。 In thread safety, the issue is almost always having synchronized access to shared resources such as static variables. 在线程安全中,问题几乎总是同步访问共享资源(例如静态变量)。

The lock which a thread acquires when declaring the method synchronized belongs to that class. 线程在声明synchronized方法时获取的锁属于该类。 Say we had two methods in a class 假设我们在一堂课中有两种方法

public synchronized void foo() {...}
public synchronized void bar() {...}

If one thread enters foo() it acquires the lock for the class, and any other thread trying to access foo() OR bar() will block until the first thread has finished. 如果一个线程进入foo()它将获取该类的锁,并且其他任何尝试访问foo() bar()的线程都将阻塞,直到第一个线程完成。 To overcome this, we can lock on seperate objects within the methods. 为了克服这个问题,我们可以锁定方法中的单独对象。

// Declare 2 objects to use as locks within the class
private Object fooLock = new Object();
private Objecy barLock = new Object();

// lock on these objects within the method bodies
public void foo {
    synchronized(fooLock) { /* do foo stuff */ }
}

public void bar() {
    synchronized(barLock) {/* do bar stuff */}
}

Now 2 threads can access the foo() and bar() simultaneously. 现在,两个线程可以同时访问foo()bar()

There's a lot of material on the web on Thread safety, I'd recommend this set of tutorials if yo want to know more about multithreading with locks / executor services and stuff. 网络上有很多关于线程安全的资料,如果您想了解有关带锁/执行器服务和东西的多线程的更多信息,我建议使用组教程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM