一旦通过就释放锁

时间:2011-07-18 10:49:48

标签: java concurrency

我有一个客户端 - 服务器架构,其中服务器的客户端轮流工作,每次客户端应该工作时传递一个参数。客户端使用参数,当完成后,参数变为“无效”,不能再用于工作。

我希望在此过程中避免运行垃圾收集器,因此我避免了对象分配。因此,计划是服务器将单个参数对象与每个客户端关联,并且每次要求客户端执行工作时,它将始终传递相同的参数。但是,这会产生一个问题,即必须将参数重新设置为“有效”,同时还要确保客户端(可能保留了对上次参数的引用)无法开始使用它(比如说) ,在被要求开始工作之前,在另一个线程中。

因此,所有参数的公共方法都被同步,并且设置了“有效”状态,然后在beginWork块内对客户端进行(同步)synchronized调用。但这会产生客户端在不知不觉中持有参数锁定的问题,如果客户端想要将其工作分成多个线程,则可能会导致问题。所以我介绍了一个单线程ExecutorService,服务器使用它来分叉对beginWork的调用,这可以确保服务器立即释放锁。但这对我来说似乎是一个糟糕的设计 - 为什么这个类需要一个完整的其他线程?

所以我的问题是:鉴于我刚刚提出的所有内容,我是否犯了一些可怕的设计错误,导致我使这个课程过于复杂化,还是真的需要这么复杂?

interface Client {
    public void doWork(Param p);
}

interface Param {
    public boolean isValid();
}

class Server {
    private final ExecutorService executor = Executors.newSingleThreadExecutor();
    private final MyParam[] params;

    private class MyParam implements Param {
        boolean isValid;
        Client client;
        Runnable task = new Runnable() {
            @Override
            public void run() {
                client.doWork(MyParam.this);
            }
        }

        @Override
        public synchronized boolean isValid() {
            return isValid;
        }
    }

    public void runClients() {
        while (true) {
            for (MyParam param : params) {
                synchronized(param) {
                    param.isValid = true;
                    // fork the client so we release the lock promptly (ugly!)
                    executor.execute(param.task);
                }

                // ... wait for the client to finish ...
            }
        }
    }
}

1 个答案:

答案 0 :(得分:0)

我通过向ReentrantLock接口添加显式Param来解决此问题。因此,我只是锁定了参数,而不是使用同步块,如果他愿意,让客户端解锁它。