如果一个类有内部类且内部类运行一个线程,这些内部类线程之间是否共享外部类的字段?

3
基本上,如果我有以下代码:
public class Outer { 
   public int counter = 0;
   public void makeNewThread() {
      Thread t1 = new Thread(new Inner());
      t1.start();
   }

   private class Inner implements Runnable {
      public void run() { //do stuff involving counter... }
   }

}

每次调用makeNewThread()时,每个线程会拥有自己的计数器版本,还是它们都共享同一个计数器版本?我认为它们会共享同一版本,因为这是内部类,但每个线程都有自己的堆栈,所以我不确定。

3
Outer 的同一实例是被共享的;除非你实例化多个 Outer 实例。未使用 volatile(或使用 AtomicInteger)修改 counter 不可取。但是,“涉及 counter 的操作”可能会安全地执行,也可能不安全。 - Elliott Frisch
volatile通常不足以处理计数器。当不同线程尝试使用"counter = counter + 1"增加值时,会出现并发问题。 - 30thh
2个回答

6

它们将共享相同的 counter


2
如果您只有一个Outer实例,那么计数器(counter)也只有一个实例,所有线程都会共享它。
重要提示! 验证从不同线程访问计数器时的并发性和可见性问题。最可能需要使用AtomicInteger代替“int”,或将所有访问代码(包括写和读操作)包装在同步块中。

我想要读取、增加和减少计数器,所以我将其设置为volatile,并将它们包装在同步方法中,即public synchronized int getCounter() {return count; }public synchronized void incrementCount() {count++}。这样做是否足够? - Mason Williams
1
是的,它会起作用。甚至有点超出了要求 :-) 如果字段是易变的,您不需要同步getter。并且两种方法(getter和setter)都必须是Outer类的方法,而不是Inner类的方法。 - 30thh
1
看一下AtomicInteger。这是一种更简单、更快速的方式来增加多线程计数器。 - 30thh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接