我已经阅读了很多关于线程安全的内容,并且对于是否有多个对象实例会影响线程安全性感到困惑。这是一个详细说明的例子:
假设我们有一个名为RGBColor的类,用户可以设置红色,绿色和蓝色的值,然后返回颜色。
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;
}
}
现在,如果程序创建了该类的多个实例,例如:
RGBColor red = new RGBcolor(255,0,0);
RGBColor blue = new RGBcolor(0,0,255);
现在问题就在这里。这些类的实例是完全独立的吗?我的意思是线程安全会成为问题吗?毕竟,据我所知,它们应该是在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:我已经更新了第二个例子,因为它有缺陷。
答案 0 :(得分:1)
这些班级的实例是完全独立的吗?我的意思是 线程安全会出问题吗?
实例之间是独立的,是的 线程安全问题是因为多个线程可以以并发方式访问一个实例,以及它们中的哪一个或两者对实例状态进行一些修改。
例如,假设您创建了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;
}
}
如何处理静态变量和方法 线程安全?
对于静态变量,与实例变量的方式相同。
例如,方法可以在实例上锁定时实现线程安全 对于静态方法,应该通过锁定类本身来实现。
答案 1 :(得分:1)
你不应该担心线程安全"这里。因为你得到了更基本的东西错误。拥有一个类的多个实例是没有意义的 - 当相应的字段都是静态的时。
换句话说:在你的第二个例子中,有一个red
和一个blue
RGBColor对象是没有意义的 - 因为你实例化的所有对象都会被相互覆盖!最后一个赢了...
除此之外,在您的第一个示例中:方法setColor()
可能会导致线程安全问题。因为该方法可能导致最终处于不一致状态(当两个线程在"相同"时间 - 但使用不同参数时)调用相同对象上的setter时。
换句话说:
答案 2 :(得分:1)
在第一种情况下,对象具有实例变量,这些对象彼此独立存在。修改一个不会影响其他人。
在第二种情况下,静态字段属于类,而不属于任何一个对象。构造函数用于创建实例?不是为了填充静态变量,为这种情况设置一个构造函数是令人困惑和不必要的。在getColor中使用它也不起作用,静态方法中没有RGBColor的实例。
对于第一种情况,如果你拿走setter并使实例变量最终,那么你的对象将是不可变的,这使得它们可以安全地在多个线程中使用。
对于第二种情况,多个线程可以覆盖彼此的工作,并且没有任何东西可以使更改对其他线程可见。 (仅仅因为线程更改了值并不意味着它立即对其他线程可见。)
如果您真的想在此类范围中使用一组值,则可以创建一个不可变对象并将其分配给静态volatile变量,以便更新对于其他线程是原子的并且是可见的。
答案 3 :(得分:0)
回答你的第一个问题。 是不同的对象在JVM中将具有单独的哈希码。但是当你考虑同时访问相同对象的事务时,你必须对对象使用线程安全(如果有对象修改)你可以使用
方法中的同步
修饰符。确保线程安全。当且仅当同一个对象由不同系统同时访问时。
回答你的第二个问题。只有当该对象的修饰符同步时,java中的静态或非静态对象才是线程安全的。除此之外,您可以使用线程池和倒计时锁来有效地处理具有许多线程的对象