简体   繁体   English

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

[英]What would happen with a synchronized block in a thread which is inside a synchronized method?

So basically what would happen if you have the following: 所以如果你有以下内容,基本上会发生什么:

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. Say, an activity needs to run in different threads which iterates over a collection. 比如说,一个活动需要在不同的线程中运行,这些线程会迭代一个集合。 Hence why creating a thread in the method with different objects. 因此,为什么在方法中使用不同的对象创建一个线程。
  2. Is this the "right" way, or perhaps there is a better way? 这是“正确的”方式,还是有更好的方法?
  3. Does this present any threats? 这会带来任何威胁吗?

The outer synchronized ensures single thread access to the process of creating the new Thread while the inner synchronized ensures single thread access to the for loop. 外部synchronized确保单线程访问创建新Thread的过程,而内部synchronized确保单线程访问for循环。

Of course you realize that as written the code doesn't make much sense because the inner this reference is targeted at your anonymous inner class. 当然,你知道,作为编写的代码并没有太大的意义,因为内this参考是针对您的匿名内部类。 I think you really mean SyncTest.this so you are synchronizing access to the SyncTest class. 我认为你真的是指SyncTest.this所以你正在同步访问SyncTest类。 Even better would be to synchronize access to mObjectList . 更好的方法是同步访问mObjectList

As written with the inner class this fixed, your Thread would block until mySyncMethod returned. 由于与内部类写this固定的,你的Thread会被阻塞,直到mySyncMethod返回。

Depending on what you are doing you might be better off using one of the Concurrent collection types rather than synchronizing access to your List as you'll get better concurrency. 根据您正在做的事情,最好使用其中一种Concurrent集合类型,而不是同步对List访问,因为您将获得更好的并发性。

Re-entrancy doesn't apply here. Re-entrancy不适用于此。 The only impact of nesting here is allowing the inner class instances to have access to the enclosing instance (including the lock being used). 这里嵌套的唯一影响是允许内部类实例访问封闭实例(包括正在使用的锁)。 The two things that are synchronized are called in different threads. 同步的两件事在不同的线程中调用。 The new thread once created will have to get chosen by the scheduler before it can run so even though these are using the same lock it would seem unlikely there would be much overlap between the two. 一旦创建的新线程必须由调度程序选择才能运行,所以即使它们使用相同的锁,看起来两者之间也不会有太多重叠。

The thread that calls mySyncMethod acquires the lock on the instance of SyncTest it's using, then it creates a new Thread, starts it, then releases the lock and goes on its way. 调用mySyncMethod的线程获取它正在使用的SyncTest实例上的锁,然后它创建一个新的Thread,启动它,然后释放锁并继续前进。

Later once the new thread starts it has to acquire the lock on the SyncTest object that started it before it can execute its run method. 稍后,一旦新线程启动,它必须获取SyncTest对象上的锁,该对象在它可以执行其run方法之前启动它。 If the lock on SyncTest is in use by something else (either the thread that just created it, another call to mySyncMethod on the same SyncTest instance, or another thread created by another call to mySyncMethod on the same SyncTest instance) then it would have to wait around to get the lock. 如果SyncTest上的锁被其他东西使用(刚刚创建它的线程,在同一个SyncTest实例上另一个调用mySyncMethod,或者在同一个SyncTest实例上另一个调用mySyncMethod创建的另一个线程),那么它将不得不等待锁定。 Then it does whatever it needs to with the list, gets to the end of the method and releases the lock. 然后它执行列表所需的任何操作,到达方法的末尾并释放锁。

There are a lot of problems here: 这里有很多问题:

  • It's unclear why you need to create your own thread rather than use a pool, or why the creating method needs to synchronize and wait around for the new thread to start before it can release its lock. 目前还不清楚为什么你需要创建自己的线程而不是使用池,或者为什么创建方法需要同步并等待新线程在它释放锁之前启动。

  • The lock on the SyncTest object is not encapsulated so other things could be acquiring it, it's unclear what things are contending for the lock. SyncTest对象上的锁没有被封装,因此其他东西可能正在获取它,目前还不清楚是什么东西争夺锁。

  • Since the list is defined as a static class member, you have more than one SyncTest object; 由于列表被定义为静态类成员,因此您有多个SyncTest对象; you're going to have separate threads messing with the same list, but using different locks, so it's hard to understand what the point of locking is. 你会有单独的线程搞乱相同的列表,但使用不同的锁,所以很难理解锁定点是什么。

But what you've shown isn't going to deadlock. 但你所展示的并不会陷入僵局。

什么都不会发生, synchronization是关于线程的,所以即使你多次重新进入同步块,如果同步的所有者是同一个线程,它们也不会阻塞。

mySyncMethod() will only run when the thread calling it can gain ownership of the lock in that instance of SyncTest. mySyncMethod()仅在调用它的线程可以获得该SyncTest实例中的锁的所有权时运行。

The run method could start in its different thread, but will block on the synchronize statement until THAT thread gains ownership of the lock for the same instance of SyncTest. run方法可以在其不同的线程中启动,但会阻塞synchronize语句,直到THAT线程获得同一SyncTest实例的锁的所有权。

(answer assumed that 'this' referred to the outer class instance, which was corrected in the edit to the original post) (回答假设'this'指的是外部类实例,在编辑中更正了原始帖子)

If you have synchronization block inside the method then the lock is on that block only. 如果方法内部有同步块,则锁定仅在该块上。 And block inside the method can have different object's lock. 并且方法内部的块可以具有不同的对象锁。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM