我可以将2个线程的操作与一个空的锁定对象同步吗?

时间:2018-07-10 14:32:46

标签: java multithreading synchronization

我在一个应用程序中有2个独立的线程,该线程执行一些图论模拟(使用Java2D),一个线程每秒执行约60次,其任务是渲染。另一个每秒执行约30次,并进行一些计算。

这两个线程共享资源。具体来说,他们共享迭代的集合。当这两个线程同时访问集合时,会发生问题。 (一个试图在其中渲染对象,而另一个正在修改集合)。这将导致ConcurrentModificationException。我尝试了一些解决方案,但我发现一个解决方案工作正常(并且易于实现),正在使用一个空对象,线程切换时将其锁定。

就像这样(示例代码):

public class Question {

static Object syncObject;

public static void main(String []Args) {

    syncObject = new Object();

    Runnable rendering = new Runnable() { //called 60 times a second
        public void run() {
            synchronized(syncObject) {
                //doRendering
            }

        }
    };
    Runnable calculations = new Runnable() { //called 30 times a second
        public void run() {
            synchronized(syncObject) {
                //doModifications
            }       
        }
    };

    Thread t1 = new Thread(rendering);
    Thread t2 = new Thread(calculations);
    t1.start();
    t2.start();
    }
}

现在,这似乎可以正常工作。这样,我不必同步正在使用的每个资源,就可以在渲染时以及“逻辑”计算更新时对其进行修改。

但是我觉得这不是一个很好的解决方案。因此,我想问一下这是否可以接受和/或是否有更合适的解决方案。 (除非我做的是完全错误的)

我也不想重写已经使用一段时间的现有代码的一半。

2 个答案:

答案 0 :(得分:0)

您可以使用 any 对象进行同步,因此您所做的正确。但是,java并发包不是使用空对象的固有锁定,而是提供了用于执行此操作的特定锁定对象。参见https://docs.oracle.com/javase/tutorial/essential/concurrency/newlocks.html

答案 1 :(得分:0)

如上所实现的那样,全局锁是适用于“粗”锁的良好解决方案。我觉得很适合您的情况。

要对其进行改进,应确保全局锁是不可变的。

private static final Object syncObject = new Object();

此方法的局限性在于,您实际上是在序列化对图形的所有访问。这将并发的可能性限制为一次仅一次。因此,在多cpu机器上,cpus处于闲置状态,而渲染和计算工作可能会花费很长时间。优点是易于实现,并且可以安全地从不同线程进行访问。

其他更难以实现的选项是:1)使用多个细粒度的锁,2)研究“无锁算法”或3)使用变异/发布方法对数据结构进行“不可变”。

以下参考文献讨论了粗粒度锁和细粒度锁:http://fileadmin.cs.lth.se/cs/education/eda015f/2013/herlihy4-5-presentation.pdf

无锁算法可能会涉及到正确实施的问题,并且并非适用于所有情况。可以阅读here

选择3,使用不可变数据结构具有许多优点(和某些限制)。这意味着图形一旦创建就无法更改。突变将通过创建一个新图来发生。为了减少内存开销,将允许图形的各部分重用。然后,这意味着渲染可以获取图形的副本,并与使图形发生变化的计算完全隔离地进行渲染。突变完成后,可以使用AtomicReference将更新的图形提供给渲染器。缺点是它需要更多的对象分配和更复杂的变异算法,但是,它允许“读取器”线程与单个变异器线程并行工作,从而从中受益。有关更多详细信息,请参见persistent vs immutable data structurehttps://docs.oracle.com/javase/8/docs/api/java/util/concurrent/atomic/AtomicReference.htmlHow does concurrency using immutable/persistent types and data structures work?