在同步方法内的线程中同步块会发生什么?

时间:2014-05-15 16:24:36

标签: java multithreading synchronization thread-safety java-threads

基本上如果你有以下内容会发生什么:

class SyncTest {
    private final static List<Object> mObjectList = new ArrayList<Object>();

    public synchronized void mySyncMethod(Object object) {
        new Thread(new Runnable() {
            public void run() {
                synchronized (SyncTest.this) {
                    for (int i = 0; i < mObjectList.size(); i++) {
                        //Do something with object
                    }
                }
            }
        }).start();
    }
}
  1. 比如说,一个活动需要在不同的线程中运行,这些线程会迭代一个集合。因此,为什么在方法中使用不同的对象创建一个线程。
  2. 这是“正确的”方式,还是有更好的方式?
  3. 这是否存在任何威胁?

5 个答案:

答案 0 :(得分:3)

外部synchronized确保单线程访问创建新Thread的过程,而内部synchronized确保单线程访问for循环。

当然你意识到编写代码并没有多大意义,因为内部this引用是针对你的匿名内部类。我认为你的意思是SyncTest.this,所以你正在同步SyncTest类的访问权限。更好的方法是同步访问mObjectList

在内部课程this修复后写入时,Thread会阻止mySyncMethod返回。

根据您的工作情况,您可能最好使用其中一种Concurrent集合类型,而不是同步对List的访问权限,因为您可以获得更好的并发性。

答案 1 :(得分:3)

Re-entrancy不适用于此处。这里嵌套的唯一影响是允许内部类实例访问封闭实例(包括正在使用的锁)。同步的两件事在不同的线程中调用。创建新线程之前必须由调度程序选择才能运行,因此即使这些线程使用相同的锁定,两者之间也不会有太多重叠。

调用mySyncMethod的线程获取它正在使用的SyncTest实例上的锁,然后它创建一个新的Thread,启动它,然后释放锁并继续前进。

稍后,一旦新线程启动,它必须获取启动它的SyncTest对象上的锁,然后才能执行其run方法。如果SyncTest上的锁被其他东西使用(刚刚创建它的线程,在同一个SyncTest实例上另一个调用mySyncMethod,或者在同一个SyncTest实例上另一个调用mySyncMethod创建的另一个线程),则必须等待锁定。然后它会对列表执行任何操作,到达方法的末尾并释放锁。

这里有很多问题:

  • 目前还不清楚为什么你需要创建自己的线程而不是使用池,或者为什么创建方法需要同步并等待新线程在它释放锁之前启动。

  • SyncTest对象上的锁没有被封装,所以其他东西可能正在获取它,目前还不清楚是什么东西争夺锁。

  • 由于列表被定义为静态类成员,因此您有多个SyncTest对象;你会有单独的线程搞乱相同的列表,但使用不同的锁,所以很难理解锁定点是什么。

但你所展示的并不会陷入僵局。

答案 2 :(得分:0)

什么都不会发生,synchronization与线程有关,所以即使你重新进入同步块很多次,如果同步的所有者是相同的线程。

答案 3 :(得分:0)

mySyncMethod()仅在调用它的线程可以获得SyncTest实例中的锁的所有权时运行。

run方法可以在其不同的线程中启动,但会在同步语句上阻塞,直到THAT线程获得同一SyncTest实例的锁的所有权。

(答案假设&#39;这个&#39;指的是外部类实例,在编辑中更正了原始帖子)

答案 4 :(得分:0)

如果方法中有同步块,则锁定仅在该块上。并且方法内部的块可以具有不同的对象锁定。