这个类线程安全吗?

时间:2010-04-16 13:58:04

标签: java concurrency multithreading

考虑这个类,没有实例变量,只有非同步的方法可以从这个信息中推断出这个类在Thread-safe中吗?

public class test{

public void test1{

// do something

}

public void test2{

// do something


}

public void test3{

// do something

}



}

8 个答案:

答案 0 :(得分:6)

这完全取决于方法变异的状态。如果他们改变没有共享状态,他们就是线程安全的。如果他们只改变本地状态,那么它们就是线程安全的。如果他们只调用线程安全的方法,那么它们就是线程安全的。

答案 1 :(得分:3)

不是线程安全意味着如果多个线程同时尝试访问该对象,则某个访问可能会从一个访问更改为下一个访问,并导致问题。请考虑以下事项:

int incrementCount() {
    this.count++;
    // ... Do some other stuff
    return this.count;
}

不会是线程安全的。为什么不呢?想象一下,线程1访问它,count增加,然后进行一些处理。在浏览函数时,另一个线程访问它,再次增加count。第一个线程,它从1到2,它现在将返回时从1到3。线程2也会看到它从1到3,所以2发生了什么?

在这种情况下,你会想要这样的东西(请记住,这不是任何特定于语言的代码,但最接近Java,只有2个我已完成线程之一)

int incrementCount() synchronized {
    this.count++;
    // ... Do some other stuff
    return this.count;
}

这里的synchronized关键字将确保只要一个线程正在访问它,就没有其他线程可以。这意味着线程1命中它,count从1到2,如预期的那样。线程2在1处理时命中它,它必须等到线程1完成。完成后,线程1返回2,然后线程2返回throguh,获得预期的3。

现在,一个类似于你所拥有的例子,无论如何都是完全线程安全的:

int incrementCount(int count) {
    count++;
    // ... Do some other stuff
    return this.count;
}

由于此处触及的唯一变量是函数的完全本地,因此不存在同时访问它的两个线程可以尝试处理从另一个更改的数据的情况。这将使其线程安全。

所以,回答这个问题,假设函数不修改特定被调用函数之外的任何东西,那么是的,该类可以被认为是线程安全的。

答案 2 :(得分:2)

从一篇关于线程安全的文章(“Java理论与实践:表征线程安全性”)中考虑以下引用:

  

实际上,线程安全的任何定义都将具有一定程度的循环性,因为它必须吸引类的规范 - 这是一个非正式的,散文描述的类,它的副作用,哪些状态有效或无效,不变量,先决条件,后置条件等。 (规范强加的对象状态的约束仅适用于外部可见状态 - 通过调用其公共方法和访问其公共字段可以观察到的状态 - 而不是其内部状态,这是其实际表示的状态。私人领域。)

     

线程安全

     

对于一个线程安全的类,它首先必须在单线程环境中正常运行。如果一个类被正确实现,这是另一种说法符合其规范的方式,那个类的对象上的任何操作序列(公共字段的读取或写入以及对公共方法的调用)都应该能够将对象放入无效状态,观察对象处于无效状态,或违反任何类的不变量,先决条件或后置条件。

     

此外,对于一个线程安全的类,当从多个线程访问时,它必须继续在上述意义上正确地运行,无论运行时环境如何调度或交错执行这些线程,没有任何额外的同步调用代码。结果是对线程安全对象的操作对于所有线程都会以固定的,全局一致的顺序出现。

所以你的类本身就是线程安全的,只要它没有任何副作用。一旦这些方法改变了任何外部对象(例如某些单例,如其他人已经提到的那样),它就不再是线程安全的了。

答案 3 :(得分:1)

取决于这些方法中发生的事情。如果他们操纵/调用任何本身不是线程安全的方法参数或全局变量/单例,那么该类也不是线程安全的。

(是的,我看到这里显示的方法没有参数,但也没有括号,所以这显然不是完整的工作代码 - 它甚至不会按原样编译。)

答案 4 :(得分:0)

是的,只要没有实例变量。仅使用输入参数和局部变量的方法调用本质上是线程安全的。您可以考虑将方法设置为静态,以反映这一点。

答案 5 :(得分:0)

如果它没有可变状态 - 它是线程安全的。如果你没有状态 - 通过关联你是线程安全的。

答案 6 :(得分:0)

不,我不这么认为。

例如,其中一个方法可以从另一个类中获取(非线程安全的)单例对象并改变该对象。

答案 7 :(得分:0)

是 - 此类是线程安全的,但这并不意味着您的应用程序是。

如果应用程序中的线程无法并发访问堆状态,则该应用程序是线程安全的。 Java中的所有对象(以及它们的所有字段)都是在堆上创建的。因此,如果对象中没有字段,那么它是线程安全的。

在任何实际应用中,对象都有状态。如果您可以保证不会同时访问这些对象,那么您就拥有了一个线程安全的应用程序。

有一些方法可以优化对共享状态的访问,例如原子变量或者使用volatile关键字,但我认为这超出了你的要求。

我希望这会有所帮助。