java - 更好地理解线程构造竞争条件

标签 java multithreading

我浏览了 Oracle tutorial关于并发和线程,遇到了以下几行:

Warning: When constructing an object that will be shared between threads, be very careful that a reference to the object does not "leak" prematurely. For example, suppose you want to maintain a List called instances containing every instance of class. You might be tempted to add the following line to your constructor: instances.add(this); But then other threads can use instances to access the object before construction of the object is complete.

谁能解释一下这些行的确切含义?

最佳答案

假设您有两个线程。左线程和右线程。左线程负责创建 worker 对象,右线程负责让它们工作。

当左线程创建完一个对象后,它将对象放在右线程可以找到的位置。它是一个变量,我们称它为 w(代表 worker),为了简单起见,假设它在某种程度上是全局可访问的。

右边的线程是一个循环。它检查 w 是否不为空。如果 w 实际上有一个非 null 值,那么方法 do 被调用。

类(class) worker 看起来像这样:

public class Worker {
    private int strength;
    private float speed;
    private String name;
    private String specialty;

    public Worker(int str, float spd, String n, String spc) {
        strength = str;
        speed = spd;
        name = n;
        specialty = spc;
    }

    public void do() {
        System.out.println("Worker " + name + " performs " + strength + " " + specialty + " at " + speed + " times per minute.");
    }
}

所以它是这样的(我已经尝试通过在一列中分别设置它们各自的命令来说明这两个线程。我希望它是可以理解的。记住,一次只有一个线程处于 Activity 状态,所以这就是为什么总是只有指令一次在一栏中)

left thread                                         | right thread
----------------------------------------------------|-----------------------------------------------------
                                                    |
Worker newWorker = new Worker(                      |               ...right thread sleeps...
                    4,                              |                           .
                    5.2f,                           |                           .
                    "mmayilarun",                   |                           .
                    "multithreaded programming"     |                           .
                );                                  |                           .
-- control jumps to constructor of Worker --        |                           .
strength = str                                      |                           .
speed = spd;                                        |       !!right thread wakes up and takes the focus!!
                                                    |   
                                                    |   if(w == null) {
                                                    |       Thread.sleep(500);
                                                    |   } else {
                                                    |       //this doesn't happen, since w is still null
                                                    |   }
                                                    |   
                                                    |           ...right thread goes back to sleep...
name = n;                                           |                           .
specialty = spc;                                    |                           .
-- control exits constructor of Worker --           |                           .
w = newWorker;                                      |       !!right thread wakes up and takes the focus!!
                                                    |       
                                                    |   if(w == null) {
                                                    |       //this doesn't happen, since w is NOT null anymore
                                                    |   } else {
                                                    |       w.do();
                                                    |   }
                                                    |

在这种情况下,一切都很好。在 worker 的构造函数完成后离开线程集 w。但这样做不是很愚蠢吗?想象一下,如果我们将 w = instanceOfWorker 调用放入 worker 构造函数中,我们可以节省多少。那么我们就不必担心记住要实际设置 w。

worker 的新构造函数如下所示:

public Worker(int str, float spd, String n, String spc) {
    w = this;
    strength = str;
    speed = spd;
    name = n;
    specialty = spc;
}

现在,代码流最终可能看起来像这样:

left thread                                         | right thread
----------------------------------------------------|-----------------------------------------------------
                                                    |
Worker newWorker = new Worker(                      |               ...right thread sleeps...
                    4,                              |                           .
                    5.2f,                           |                           .
                    "mmayilarun",                   |                           .
                    "multithreaded programming"     |                           .
                );                                  |                           .
-- control jumps to constructor of Worker --        |                           .
w = this;   // danger!!                             |                           .
strength = str;                                     |                           .
speed = spd;                                        |       !!right thread wakes up and takes the focus!!
                                                    |   
                                                    |   if(w == null) {
                                                    |       //this doesn't happen, since w is NOT null at this point
                                                    |   } else {
                                                    |       w.do(); //here, w is not yet a fully initialized object,
                                                    |       //and the output is not the expected (if it works at all)
                                                    |   }
                                                    |   
                                                    |           ...right thread goes back to sleep...
name = n;                                           |                           .
specialty = spc;                                    |                           .
-- control exits constructor of Worker --           |

oracle 有一个更复杂的示例,其中包含一组称为“实例”的对象。这是唯一的区别。

关于java - 更好地理解线程构造竞争条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9707437/

相关文章:

java - 如何解决应用程序中的 Java JLabel 问题?

C++ - 不同线程通知的 std::condition_variable

c# - 为什么异常中断应用程序池?

c# - .NET 线程返回值?

java - Postgres 不允许我的应用程序连接

java - 我是否使 Java 中的简单解决方案变得过于复杂?

java - 将变量从一个jsp页面传递到另一个页面?

java - OSGi 线程永远不会停止运行,为线程定义了固定的生命周期

multithreading - 在 osx 和 ios 的主线程上运行循环

java - Android - 你能为 SQLite 结果更新 Cursor 吗?