Java中同一对象不同实例的多线程

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3098786/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 16:26:46  来源:igfitidea点击:

Multi-Threading on different instances of same object in Java

javamultithreadingsynchronizationrace-condition

提问by TacB0sS

I've learned that every class byte code is been loaded to the memory once for each class loader, thus when a thread is executing the byte code of some method, and another thread comes along?

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

1thread -> 1instance - of classFoo== no problem.

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

Xthreads -> 1instance - of classFoo== need to be handled this is clear.

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

Xthreads -> X respectiveinstances - of classFoo== ????

X 个线程 -> X 个各自的实例 -Foo== ????

should I make sure nothing is messed up in the method? if the method uses a instancelevel variables, can I be sure it will use the right ones?

我应该确保方法中没有任何问题吗?如果该方法使用实例级变量,我可以确定它会使用正确的变量吗?

Update:

更新:

I see my question was not clear to some, here is an example with numbers

我看到有些人不清楚我的问题,这是一个数字示例

I have an object of class type Foowhich has no synchronization!!

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

I have 5 instances of that Foowith 5 threads running for/in each of them, and accessing instancelevel parameters for example:

我有Foo 的5 个实例,每个实例有 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
     }
}

I'm asking is there a problem here, since there is only 1byte code of this class and 5instances of this object that access this byte code, so if I want to prevent them from overlapping on the same byte code, what should I do?

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

Thanks, Adam.

谢谢,亚当。

采纳答案by Tim Bender

I've learned that every class byte code is been loaded to the memory once for each class loader, thus when a thread is executing the byte code of some method, and another thread comes along?

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

Class loading and byte code is irrelevant here. Byte code is a set of assembly-like instructions which the JVM interprets and compiles into native machine code. More than one thread can safely follow the instruction sets encoded into the byte code.

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

1 thread -> 1 instance - of class Test, no problem

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

Mostly correct. If there is only a single Thread, then there is not any immediate need to make anything thread safe. However, ignoring thread safety would limit growth and re-usability.

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

X threads -> 1 instance - of class Test, need to be handled this is clear.

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

Well, yes, for thread visibility reasons and to ensure that critical regions are executed atomically, using synchronization or locking techniques is fairly important. Of course, it all depends right?! If your class doesn't have state (instance or class variables), then you don't really need to make it thread-safe (think utility class like Java's Executors, Arrays, Collectionsclasses).

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

X threads -> X respective instances - of class Test, ????

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

If each thread has its own instance of class Test, and no single instance is shared amongst more than one thread, then this is the same as your first example. If an instance of Test is referenced by two or more threads, then this is the same as your second example.

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

if the method uses a class level variables, can I be sure it will use the right ones?

如果该方法使用类级别变量,我可以确定它会使用正确的变量吗?

Class variables ARE staticvariables in Java. There are already two answers posted which emphasize the importance of using synchronizedto prevent more than one thread from modifying a class variable at the same time. Not mentioned is the importance of using synchronizedor volatileto make sure you don't see a stale version of the class variable.

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

回答by davetron5000

You need to synchronize on the shared resource. If that resource is a class-level field, you should synchronize on the class itself:

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

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++;
    }
  }
}

Note that {{java.util.concurrent}} provides many more ways to protected shared data than Java's {{synchronized}} keyword. Look into it, as it might be what you want.

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

(For anyone that wants to claim that int incrementing is already thread-safe, please note this is just an example and the basic concept can be applied to anything.)

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

回答by Abhinav Sarkar

Adding to dave's answer, if you have multiple static methods that work on different static members, it is better to synchronize on separate static objects.

添加到 dave 的答案中,如果您有多个用于不同静态成员的静态方法,最好在单独的静态对象上进行同步。

public class Foo {
  private static int someNumber = 0;
  private static int otherNumber = 0;
  private static final Object lock1 = new Object();
  private static final Object lock2 = new Object();

  public static void incSomeNumber() {
    synchronized (lock1) {
      someNumber++;
    }
  }

  public static void incOtherNumber() {
    synchronized (lock2) {
      otherNumber++;
    }
  }
}

In this way, two different threads can call incSomeNumberand incOtherNumberat the same time without getting stuck on synchronization.

通过这种方式,两个不同的线程可以同时调用incSomeNumberincOtherNumber,而不会卡在同步上。



EDIT

编辑

Here is the same example with AtomicInterger. Note that no explicit locking is required. All operations on AtomicIntergers are atomic and implemented using hardware operations. So they result in better performance.

这是与AtomicInterger. 请注意,不需要显式锁定。AtomicIntergers上的所有操作都是原子的,并使用硬件操作实现。因此,它们会带来更好的性能。

import java.util.concurrent.atomic.AtomicInteger;

public class Foo {
  private static AtomicInteger someNumber = new AtomicInteger(0);
  private static AtomicInteger otherNumber = new AtomicInteger(0);

  public static int incSomeNumber() {
    return someNumber.incrementAndGet();
  }

  public static int incOtherNumber() {
    return otherNumber.incrementAndGet();
  }
}

回答by bwawok

All threads should go to the same class loader. 10 threads using FOo.class, all 10 will have the same exact object. The only way you would get the same class in different classloaders would be if

所有线程都应该进入同一个类加载器。使用 FOo.class 的 10 个线程,所有 10 个都将具有完全相同的对象。在不同的类加载器中获得相同类的唯一方法是

a) You wrote your own code that did class loader magic
b) You did something weird like include your code both inside a war, and inside of a shared tomcat lib folder... and did the right sequence of events to cause 2 copies to be loaded from different places.

a)您编写了自己的代码来实现类加载器魔术
b)您做了一些奇怪的事情,例如将您的代码包含在战争中和共享的 tomcat lib 文件夹中......并执行了正确的事件序列以导致 2 个副本从不同的地方加载。

In all normal cases.. you make a class, there is exactly 1 copy of the class object, and all synchronization on (this) will be across your entire application.

在所有正常情况下..您创建一个类,该类对象正好有 1 个副本,并且 (this) 上的所有同步都将跨越您的整个应用程序。

回答by nihar m.

And I think, instance variable as local variable is unique to each thread. So by default it is thread safe.But yes, it is still needed to be taken care by synchronization.

而且我认为,作为局部变量的实例变量对于每个线程都是唯一的。所以默认情况下它是线程安全的。但是是的,它仍然需要通过同步来照顾。