java对基本变量的多线程访问
我知道,从不同线程同时访问同一对象,而不进行同步,通常是一件坏事。但是这个案子呢 我有多个线程在运行(考虑两个线程,ThreadA和ThreadB)。我还有一个静态类来记录线程做某事的次数java对基本变量的多线程访问,java,multithreading,primitive-types,Java,Multithreading,Primitive Types,我知道,从不同线程同时访问同一对象,而不进行同步,通常是一件坏事。但是这个案子呢 我有多个线程在运行(考虑两个线程,ThreadA和ThreadB)。我还有一个静态类来记录线程做某事的次数 public class Counter { static private int counter=0; static public void incCounter() { counter++; } } 如果ThreadA和ThreadB都调用Counter.incCounter(),会
public class Counter {
static private int counter=0;
static public void incCounter() {
counter++;
}
}
如果ThreadA和ThreadB都调用Counter.incCounter(),会发生什么情况?这不安全
每个线程将尝试读取计数器
,向其添加一个计数器,然后写回结果。您无法保证这些读取和写入的顺序,甚至无法保证结果对每个线程都是可见的
特别是,一种失败情况是每个线程读取值0,将其递增为1,然后写回值1。即使在两个线程尝试递增计数器值后,这也会使计数器值为1
考虑改用.incrementAndGet()。不管它是静态对象还是实例:如果从多个线程中更改它,就会出现问题。它的值将是1或2。在此上下文中,静态变量和非静态变量之间没有区别。为避免冲突,请使用关键字synchronized
public class Counter {
static private int counter=0;
public static synchronized void incCounter() {
counter++;
}
}
此关键字只允许一个线程调用incCounter()。Dave是正确的,但快速修复方法只是将“synchronized”关键字添加到该方法描述中;如果多个线程调用该方法,它们将在方法边界处阻塞,直到其中一个(赢得比赛的)增加并存在,然后第二个调用方将进入 这很像在单例类上设计一个好的“getInstance()”方法;您通常希望它被同步,这样您就不会出现这样的情况:2个以上的线程进入该方法,所有线程都看到“instance”为null,然后所有线程都创建一个新实例,将其分配给本地成员并返回它 在这种情况下,您的线程可能会以对“相同”实例的不同引用结束。因此,同步代码块,仅允许第一个线程在实例为null时创建实例,否则总是向所有调用方返回相同的实例 if(instance==null)检查加上返回值很便宜;在微秒的数量级上,我相信将来调用getInstance(或者在您的示例incCounter中)时,不需要回避synchronized关键字(如果需要);这就是为什么
也就是说,如果你不能抽出几微秒。。。那么,你可能用错了语言:没有什么灾难性的,但计数器将不是准确的总和。@不名誉:取决于你所认为的“灾难性”。如果某个关键的东西依赖于计数器,它将失败。为什么从不同线程访问同一个对象是一件坏事?“若需要,那个么它是必要的。”Steve Kuo-question澄清说,不同步的并发访问是不好的。显然,从多个线程进行适当的协调访问是不行的。对于轻量级性能计数器,我不使用任何类型的线程安全性,因为我知道计数器可能会稍微超出范围,但它的成本最低。这个计数器只是用来表示。嗯,我不知道它的存在。每天都是上学的日子。谢谢。这将起作用,但与
AtomicInteger
相比效率较低。