线程安全:类的实例

时间:2015-11-01 06:47:23

标签: java multithreading

以下是Java concurrency in Pratice的第一个代码段。我不知道这个类是不是线程安全的?每次线程需要调用方法getNext()时,它会不会首先创建此类的实例?两个线程可以共享此类(barring explicit share)?

的相同实例
@NotThreadSafe
public class UnsafeSequence {
private int value;
/** Returns a unique value. */
public int getNext() {
return value++;
}
 }

4 个答案:

答案 0 :(得分:3)

  

我不明白这个类是不是线程安全的?

您现在可能已经回答了这个问题,但为了完整起见,我将其包含在此处。)

问题是value++声明。这是一个多部分声明。

  1. 读取value的值。
  2. 读取值加1。
  3. 新值存储在value
  4. 此序列可以由另一个线程混合。假设value5。如果两个线程调用getNext()(在同一个实例上),那么当完成后,您会期望value7。但是,如果两个线程在任何线程执行步骤3之前已完成步骤1和2,则它们都将值6写入value

    • 线程1执行步骤1 - 读取5
    • 线程2执行步骤1 - 读取5
    • 线程2执行第2步 - 按5
    • 递增1
    • 线程2执行步骤3 - 保存值6
    • 主题1执行第2步 - 按5
    • 增加1
    • 主题1执行第3步 - 保存值6
      

    每次线程需要调用方法getNext()时,它都会胜出   首先创建这个类的实例?

    不是每一次。这将是new UnsafeSequence().getNext()一遍又一遍,这是没有意义的。但也许这并不完全是你的意思。每个线程都可以拥有自己的类实例,并在其上调用getNext()。在那种情况下没有问题。

      

    两个线程可以共享此类的相同实例(禁止显式   份额)?

    不,必须以某种方式共享实例。但它可以在你不知情的情况下分享。例如,某些类可能具有static方法,该方法返回UnsafeSequence的实例。您不会知道它是否是每次返回的相同实例,或者每次调用是否创建了新实例。 除非,否则会在某处记录。

    在API文档中讨论类是否是线程安全的讨论是指在线程之间共享实例的情况。如果某个实例未共享,则可以在多线程应用程序中使用它,只要,因为它只有一个线程可用并且只能使用它。

答案 1 :(得分:1)

是的,显然2个或更多线程可以同时访问同一个对象。那就是当竞争条件发生时,即当多个线程争用共享资源时(在你的情况下是UnsafeSequence的相同对象)。

EG:

UnsafeSequence seq = new UnsafeSequence();
// both thread instances share same object
Thread t1 = new MyThread(seq);
Thread t2 = new MyThread(seq);
t1.start();
t2.start();

// run method for above `MyThread` class:
public void run() {
   while(some condition) {
    // some work
    System.out.println(seq.getNext()); // sequence is unpredictable
   }
}

如果不同的线程访问不同的对象实例,则不存在线程安全问题。

答案 2 :(得分:1)

  

两个线程可以共享此类的相同实例(禁止显式共享)吗?

我认为这是你误解的根源。

基本上,如果两个线程都使用对给定实例的引用,则它们共享实例。他们如何设法获得参考并不重要。 "显式"之间没有真正的区别。和其他分享参考的方式。

该示例的基本假设是两个线程> do<以某种方式设法共享实例。

(如果他们没有,或者确实如果只有一个线程,则线程安全或类别不会成为问题。要使用Goetz等人的术语,线程安全性为a"线程受限"对象无关紧要。)

答案 3 :(得分:0)

由于Java允许多线程语言(多个线程并行运行以完成程序执行) 在多线程环境中,java对象的同步或java类的同步变得极为重要。

同步是一种允许一次只允许一个线程访问资源的功能。它适用于锁定的概念。

  ThreadDemo T1 = new ThreadDemo(safeSeq);
  ThreadDemo T2 = new ThreadDemo(safeSeq);

在上面的代码中,我们为这两个线程提供了单独的锁

public class UnsafeSequence {
private int value;
/** Returns a unique value. */
public int getNext() {
return value++;
   }
 }


class ThreadDemo extends Thread {

UnsafeSequence  safeSeq;

 public void run() {

 some code here

 safeSeq.getNext();

 }

}

public class TestThread {
public static void main(String args[]) {

  UnsafeSequence safeSeq = new UnsafeSequence();

  ThreadDemo T1 = new ThreadDemo(safeSeq);
  ThreadDemo T2 = new ThreadDemo(safeSeq);

  T1.start();
  T2.start();

     }
}