我知道同时从不同的线程访问同一个对象,没有同步,通常是一件坏事。但是这个案子呢:
我有多个线程在运行(考虑两个,ThreadA和ThreadB)。我也有这个静态类来保持Thread执行某些操作的次数。
public class Counter {
static private int counter=0;
static public void incCounter() {
counter++;
}
}
如果ThreadA和ThreadB都调用Counter.incCounter()?
会发生什么答案 0 :(得分:11)
这不安全。
每个线程都会尝试读取counter
,向其中添加一个,然后回写结果。您无法保证这些读取和写入的顺序,或者即使结果对每个线程都可见。
特别是,一个失败的情况是每个线程读取值0,将其递增为1,并写回值1.即使在两个线程尝试递增它之后,这也会使计数器的值为1。
请考虑使用AtomicInteger。incrementAndGet()代替。
答案 1 :(得分:1)
它的值可以是1或2.在这种情况下,静态和非静态变量之间没有区别。
答案 2 :(得分:0)
无论是静态对象还是实例都无关紧要:如果从多个线程更改它,就会出现问题。
答案 3 :(得分:0)
避免冲突使用关键字synchronized。
public class Counter {
static private int counter=0;
public static synchronized void incCounter() {
counter++;
}
}
此关键字只允许一个时间线程调用incCounter()。
答案 4 :(得分:0)
Dave是正确的,但快速修复只是将“synchronized”关键字添加到该方法描述中;如果多个线程调用该方法,它们将在方法边界处阻塞,直到内部的一个(赢得比赛)增加并存在,然后第二个调用者将进入。
这就像在Singleton类上设计一个好的“getInstance()”方法一样;你通常希望它被同步,所以你没有2+个线程进入方法的情况,ALL看到“instance”为null,然后ALL创建一个新实例,将它分配给本地成员并返回它
在这种情况下,您的线程可能会以“相同”实例的不同引用结束。因此,您同步代码块,只允许第一个线程创建实例(如果它为null),否则始终将相同的实例返回给所有调用者。
if(instance == null)检查加上回报便宜;对于将来调用getInstance(或者在你的示例中为incCounter),我相信微秒的顺序,所以如果你需要,不需要回避synchronized关键字;这就是它的用途。
话虽如此,如果你不能节省微秒......那么你可能会使用错误的语言:)