在 Java 中对同一对象的不同实例进行多线程处理

我已经了解到,每个类字节代码对于每个类加载器都加载到内存中一次,因此当一个线程正在执行某个方法的字节代码时,另一个线程出现?

1 个线程 -> 1 个实例 - Foo == 没有问题。

X 线程 -> 1 个实例 - 的类 Foo == 需要处理这一点很清楚。

X 线程 - > X 个相应的实例 - Foo == ????

我应该确保方法中没有任何东西被搞砸吗?如果该方法使用实例级变量,我能否确定它将使用正确的变量?

更新:

我看到我的问题对某些人来说不清楚,这里有一个数字的例子

我有一个类类型的Foo对象,它没有同步!

我有5个该Foo的实例,每个实例运行5个线程,并访问实例级参数,例如:

class FOO {
     private SomeObject someObject=new SomeObject();

     private void problematicMethod(Data data) {
         someObject.doSomethingWithTheData(data);
         data.doSomethingWithSomeObject(someObject); 
// any way you want it use the data or export the data
     }
}

我问这里是否存在问题,因为这个类只有1个字节代码和这个对象的5个实例访问这个字节代码,所以如果我想防止它们在同一字节代码上重叠,我该怎么办?

谢谢 亚当


答案 1

我已经了解到,每个类字节代码对于每个类加载器都加载到内存中一次,因此当一个线程正在执行某个方法的字节代码时,另一个线程出现?

类加载和字节码在这里无关紧要。字节码是一组类似汇编的指令,JVM 解释这些指令并将其编译为本机机器代码。多个线程可以安全地遵循编码到字节代码中的指令集。

1 线程 - > 1 个实例 - 类测试,没问题

大部分是正确的。如果只有一个线程,则无需立即使任何线程安全。但是,忽略线程安全会限制增长和可重用性。

X线程 -> 1 个实例 - 类 Test,需要处理这一点很清楚。

好吧,是的,出于线程可见性的原因并确保关键区域以原子方式执行,使用同步或锁定技术非常重要。当然,这一切都取决于对吗?!如果你的类没有状态(实例或类变量),那么你实际上不需要让它成为线程安全的(想想像Java的,,类这样的实用程序类)。ExecutorsArraysCollections

X 线程 - > X 个各自的实例 - 类测试,????

如果每个线程都有自己的类 Test 实例,并且没有在多个线程之间共享单个实例,则这与第一个示例相同。如果 Test 的实例由两个或多个线程引用,则这与第二个示例相同。

如果该方法使用类级变量,我能确定它将使用正确的变量吗?

类变量是 Java 中的变量。已经发布了两个答案,它们强调了使用以防止多个线程同时修改类变量的重要性。没有提到的是使用或确保您看不到类变量的过时版本的重要性。staticsynchronizedsynchronizedvolatile


答案 2

您需要在共享资源上进行同步。如果该资源是类级字段,则应在类本身上进行同步:

public class Foo {
  private static int someNumber = 0;
  // not thread safe
  public void inc_unsafe()  { 
    someNumber++;
  }

  // not thread safe either; we are sync'ing here on an INSTANCE of
  // the Foo class
  public synchronized void inc_also_unsafe()  { 
    someNumber++;
  }

  // here we are safe, because for static methods, synchronized will use the class
  // itself
  public static synchronized void inc_safe()  { 
    someNumber++;
  }

  // also safe, since we use the class itself
  public static synchronized void inc_also_safe()  { 
    synchronized (Foo.class) {
      someNumber++;
    }
  }
}

请注意,{{java.util.concurrent}} 提供了比 Java 的 {{synchronized}} 关键字更多的方法来保护共享数据。看看它,因为它可能是你想要的。

(对于任何想要声称int增量已经是线程安全的人,请注意这只是一个例子,基本概念可以应用于任何事情。)