在Synchronization中关系之前会发生什么?什么是过早的物体泄漏?

时间:2013-08-07 15:11:37

标签: java multithreading

我正在阅读SynchronizedMethodsOracleDoc,我无法理解这个概念。 它说的。

  

警告:构建将在其间共享的对象时   线程,要非常小心,对对象的引用不会   过早地“泄漏”。例如,假设您要维护List   调用包含每个类实例的实例。你可能是   试图将以下行添加到构造函数中:   instances.add(本);但其他线程可以使用实例   在构造对象完成之前访问对象。

这是什么意思?

它还指出: -

  

其次,当同步方法退出时,它会自动建立   与任何后续调用a之前发生的关系   同一对象的同步方法。

关系之前发生的意义是什么?

有人可以详细说明这两点吗?感谢。

3 个答案:

答案 0 :(得分:2)

第一个问题:

import java.util.LinkedList;
import java.util.List;

public class Example implements Runnable {

    private static LinkedList<ListEntry> objList;

    public static class ListEntry {
        public int var = -1;
        public ListEntry(List<ListEntry> objList, int var) {
            synchronized (objList) {
                objList.add(this);
            }
            try {
                Thread.sleep(2);
            } catch (InterruptedException e) {}
            this.var = var;
        }
    }

    public static void main(String[] args) {
        objList = new LinkedList<>();
        new ListEntry(objList, 1);
        for (int i=0; i < 100; i++) {
            new Thread(new Example()).start();
        }
    }

    public void run() {
        for (int i=0; i < 1000; i++) {
            ListEntry lastEntry;
            synchronized (objList) {
                lastEntry = objList.getLast();
            }
            try {
                Thread.sleep(2);
            } catch (InterruptedException e) {}
            int lastVar = lastEntry.var;
            new ListEntry(objList, lastVar + 1);
            System.out.println(lastVar);
            if (lastVar < 0)
                throw new RuntimeException("lastVar = " + lastVar);
        }
    }
}

如果运行此代码,将不时抛出RuntimeException,因为添加到列表的最后一个对象尚未完成构造,因此它的var实例将具有初始-1值。这可能是因为您在构造函数中“泄露”了对象引用(this)。无法想出一个更好的例子。

第二个问题: 同步方法保证在任何后续调用该方法之前完成(已经发生)。不知道如何更好地描述它。

答案 1 :(得分:2)

过早泄漏

泄漏对尚未完全创建的对象的引用。

示例:

class Someclass{

   public SomeClass(List list){
        list.add(this); //this is leaked outside before complete creation, constructor is still not complete

        //do some other chores to create this object
   }
}

一些主题2:

listPassedToSomeclass //Thread is using this list and working on something

现在从构造函数调用添加列表时,您在列表中发布了this引用,该引用由其他线程共享,现在它甚至可以在构造函数结束之前看到列表中添加了此引用(这意味着对象未处于稳定状态且未正确创建。

线程2有可能在使用对象时会遇到各种奇怪的行为,因为状态会不稳定。所以避免泄漏引用。

发生之前

enter image description here

答案 2 :(得分:1)

假设您有实例列表。在Object的构造函数中,将this添加到该列表中。

文章说实例在多个线程之间共享。因此,在您添加this时,其他线程可以访问它。但是,由于您要在对象的构造函数中添加它,因此该对象尚未完全实例化(直到它从构造函数返回)。

所以基本上你要共享一个未完全实例化的对象的引用。

对于第二点,在关系之前发生的事件意味着保证同步对象块对访问该数据的其他线程可见,因为它总是在可以获取同步对象时执行。不确定我是否正确解释了这一点。

看看这个: http://docs.oracle.com/javase/tutorial/essential/concurrency/memconsist.html