在非静态方法中使用同步块锁定实例

时间:2018-09-27 01:10:31

标签: multithreading synchronization thread-safety synchronized thread-synchronization

通过下面的代码,我有两个类A的实例-a1和a2。并分别在两个实例上调用方法foo()。

在foo()方法中有一个同步块,该块已锁定在调用对象上。由于这是一个实例级锁定,因此这两种方法应同时开始执行,因为它们是从两个单独的实例中调用的。但是,它们是按顺序执行的。

是因为两个实例都从同一个线程主线程调用吗?

代码更改:使类A实现Runnable,将foo()重命名为run(),从main分叉线程t,从主线程调用a1.run(),从线程t调用a2.run()。尽管从两个线程(主线程和线程t)调用了两个A实例a1和a2,但同步块似乎已被锁定。

我的理解是,“ this”是指调用Runnable实例,该实例不同,甚至线程也不同。因此,Thread.sleep不应使其​​他线程被阻塞。然后,为什么运行的两个调用不是同时发生的?

  

预期输出(应并行执行)

    func spawnShape() {
        // 1
        var geometry:SCNGeometry
        let positions = [
            SCNVector3(-2, 1.5, 0), //0
            SCNVector3(-2, 1.5, 0), //1
            SCNVector3(2, -1.5, 0), //2
            SCNVector3(2, 1.5, 0), //3
            SCNVector3(-2, 1.5, 0.4), //4
            SCNVector3(2, 1.5, 0.4) //5
        ]
        let source = SCNGeometrySource(vertices: positions)
        let indices:[CInt] = [
            0, 2, 1,
            0, 3, 2,
            0, 4, 5,
            0, 5 ,3,
            4, 1, 2,
            4, 2, 5
            ]
        let element = SCNGeometryElement(indices: indices, primitiveType:.triangles)

        // 4
        geometry = SCNGeometry(sources: [source], elements: [element])
        let geometryNode = SCNNode(geometry: geometry)

        // 5
        scnScene.rootNode.addChildNode(geometryNode)
    }
}
  

实际输出(按顺序执行)

main <time> Inside A.run
Thread-0 <time> Inside A.run
Thread-0 <time+4s> Exiting A.run
main <time+5s> Exiting A.run

main <time> Inside A.run
main <time+5s> Exiting A.run
Thread-0 <time+5s> Inside A.run
Thread-0 <time+9s> Exiting A.run 

2 个答案:

答案 0 :(得分:1)

  

是因为两个实例都从同一实例被调用   主线程?

是的。调用Thread.sleep()是同步的,除非中断,否则它将在持续时间内阻止当前线程。您直接调用a1.foo(),它将在持续时间内阻止主线程,这是您看到的结果。创建单独的线程并在每个线程中调用foo(),您将看到期望的行为。

答案 1 :(得分:1)

您开始在启动线程之前同步运行a1,当然您会在主线程上获得a1的输出,因为在a1完成之前,它无法到达线程启动语句。

尝试在主线程上运行a2之前先启动运行a1的线程,看看会得到什么。

您还应该注意,线程调度可能会延迟,并且调用Thread#start不会立即在单独的线程上开始执行,而是将其排队给系统线程调度程序。您可能还想考虑使用诸如CyclicBarrier之类的同步设备,以便在运行a2的线程和运行a1的主线程之间进行协调,否则您可能 still < / em>会获得完全相同的结果,即使您似乎在a1之前启动线程来运行a2