java 中的线程安全和实例

Thread-Safety and Instances in java

我已经阅读了很多关于线程安全的文章,并且对一个对象的多个实例是否会影响线程安全感到困惑。下面举例说明:
假设我们有一个名为 RGBColor 的 class,用户可以设置红色、绿色和蓝色的值,然后 return 颜色。

Public Class RGBColor {
    private int red;
    private int green;
    private int blue;
    Public RGBColor(int red, int green, int blue){
       this.red = red;
       this.green = green;
       this.blue = blue;
    }
    Public void setColor(int red, int green, int blue){
       this.red = red;
       this.green = green;
       this.blue = blue;
    }
    Public RGBColor getColor(){
       return this;
    }
}

现在,如果程序创建了多个 class 实例,例如:

RGBColor red = new RGBcolor(255,0,0);
RGBColor blue = new RGBcolor(0,0,255);

现在问题来了。 class 的这些实例是否完全独立?我的意思是线程安全会成为一个问题吗?毕竟据我了解,它们应该是完全不同的对象,在 RAM 中具有不同的分配。

另一个问题是变量和方法是否是静态的,例如

Public Class RGBColor {
    private static int RED;
    private static int GREEN;
    private static int BLUE;

    Public static void setColor(int red, int green, int blue){
       RED = red;
       GREEN = green;
       BLUE = blue;
    }
}

在线程安全方面如何处理静态变量和方法?

ps:我已经更新了第二个例子,因为它有缺陷。

Are these instances of the class are totally independent? I mean would thread safety would be an issue?

实例之间是独立的,是的。
线程安全问题是因为多个线程可能以并发方式访问一个实例,并且其中一个或两个线程对实例状态进行了一些修改。

例如,假设您创建了一个 RGBColor 的实例,并且多个线程可以操作该实例。
现在,我们要求您 setColor() 调用不应与自身的其他调用交错。
在那里,你有一个竞争条件,你应该处理这个。
要处理它,您可以使用 synchronized 语句包围 setColor() 语句,并使字段 volatile 确保始终更新每个线程的内存:

private volatile int red;
private volatile int green;
private volatile int blue;
...
public void setColor(int red, int green, int blue){
   synchronized (this){
     this.red = red;
     this.green = green;
     this.blue = blue;
   }
}

How are the static variables and methods would be handled when it comes to thread safety?

对于静态变量,与实例变量相同。

对于实例方法,可以在实例上的锁上实现线程安全。
对于静态方法,应该在 class 本身的锁上实现。

你不应该担心 "thread safety" 这里。因为你得到的是更基本的东西错误。拥有一个 class 的多个实例是没有意义的 - 当相应的字段都是静态的时。

换句话说:在你的第二个例子中,拥有一个 red 和一个 blue RGBColor 对象是没有意义的——因为你实例化的所有对象都会相互覆盖!最后一个获胜...

除此之外,在您的第一个示例中:方法 setColor() 可能会导致线程安全问题。因为该方法可能导致您最终处于不一致状态(当两个线程在 "same" 时间调用 相同 对象上的 setter - 但是不同的说法)。

换句话说:

  • 首先花点时间学习一下 static 是什么,以及为什么你的第二个代码输入如此糟糕 "bad"
  • 然后理解:一旦 "shared" 数据可被多个线程访问,线程安全就很重要。因为那时你必须确保对 "shared" 数据的 read/write 操作总是定义明确的。

第一种情况,对象有实例变量,对象是相互独立存在的。修改一个不会影响其他。

在第二种情况下,静态字段属于class,不属于任何一个对象。构造函数用于创建实例?不是为了填充静态变量,在这种情况下有一个构造函数是令人困惑和不必要的。同样在 getColor 中使用它也不起作用,静态方法中没有 RGBColor 的实例。

对于第一种情况,如果您取消设置器并将实例变量设为最终变量,那么您的对象将是不可变的,从而使它们可以安全地用于多线程。

对于第二种情况,多个线程可以覆盖彼此的工作,并且没有任何东西可以让其他线程看到更改。 (仅仅因为一个线程改变了一个值并不意味着它立即对其他线程可见。)

如果你真的想要这个 class 范围内的一组值,你可以创建一个不可变对象并将其分配给静态 volatile 变量,这样更新将是原子的并且对其他线程可见。

回答你的第一个问题。 YES 不同的对象在 JVM 中会有不同的哈希码。但是,当您考虑同时访问同一对象的事务时,您将不得不对对象使用线程安全(如果有对象修改),您可以使用

synchronized

methods.to 中的修饰符确保线程安全。当且仅当不同系统同时访问同一个对象。

回答你的第二个问题。 java 中的静态或非静态对象只有在该对象的修饰符 同步 时才是线程安全的。除此之外,您可以使用线程池和倒计时闩锁来有效地处理具有多个线程的对象