java中的线程安全和实例

时间:2017-10-24 10:44:35

标签: java multithreading static thread-safety multiple-instances

我已经阅读了很多关于线程安全的内容,并且对于是否有多个对象实例会影响线程安全性感到困惑。这是一个详细说明的例子:
假设我们有一个名为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:我已经更新了第二个例子,因为它有缺陷。

4 个答案:

答案 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时。

换句话说:

  • 首先花些时间了解 static 的内容,以及为什么你的第二个代码输入如此严重"糟糕"
  • 然后明白:线程安全只要#34;共享"数据可供多个线程访问。因为那时你必须确保对那个"共享"的读/写操作。数据总是很明确。

答案 2 :(得分:1)

在第一种情况下,对象具有实例变量,这些对象彼此独立存在。修改一个不会影响其他人。

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

对于第一种情况,如果你拿走setter并使实例变量最终,那么你的对象将是不可变的,这使得它们可以安全地在多个线程中使用。

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

如果您真的想在此类范围中使用一组值,则可以创建一个不可变对象并将其分配给静态volatile变量,以便更新对于其他线程是原子的并且是可见的。

答案 3 :(得分:0)

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

  

同步

方法中的

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

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