简体   繁体   English

一旦通过就释放锁

[英]Releasing a lock as soon as it is passed

I have a client-server architecture where the server has its clients do work in turns, passing a parameter each time a client is supposed to do work.我有一个客户端-服务器架构,其中服务器让其客户端轮流工作,每次客户端应该工作时传递一个参数。 The client does work with the parameter, and when it is done, the parameter becomes "invalid" and can no longer be used to do work.客户端确实使用参数,当它完成时,参数变为“无效”,不能再用于工作。

I'd like to avoid running the garbage collector while this is going on, and so I'm avoiding object allocations.我想避免在此过程中运行垃圾收集器,因此我避免 object 分配。 So the plan is that the server will associate a single parameter object with each client, and will always pass the same parameter every time the client is asked to do work.所以计划是服务器将单个参数 object 与每个客户端关联,并且每次要求客户端执行工作时总是传递相同的参数。 However, this creates the problem that the parameter will have to be re-set to "valid" while also ensuring that the client (who may have kept a reference to the parameter from the last time around) can't start using it (say, in a different thread) before it is asked to begin doing work.但是,这会产生一个问题,即必须将参数重新设置为“有效”,同时还要确保客户端(可能上次保留对参数的引用)无法开始使用它(比如,在不同的线程中)在被要求开始工作之前。

So all of the parameter's public methods are synchronized, and the "valid" state is set, followed by a (synchronous) beginWork call to the client, inside a synchronized block.因此,所有参数的公共方法都是同步的,并且设置了“有效” state,然后在synchronized块内对客户端进行(同步) beginWork调用。 But this creates the problem that the client will unknowingly hold the parameter's lock, which could cause problems if the client wants to split its work into multiple threads.但这会产生客户端在不知不觉中持有参数锁的问题,如果客户端想要将其工作拆分为多个线程,这可能会导致问题。 So I introduced a single-threaded ExecutorService which the server uses to fork off the call to beginWork , which ensures that the server will release the lock promptly.所以我引入了一个单线程的ExecutorService ,服务器用它来分叉对beginWork的调用,这确保了服务器会及时释放锁。 But this seems like a bad design to me -- why should this class need a whole other thread?但这对我来说似乎是一个糟糕的设计——为什么这个 class 需要一个完整的其他线程?

So my question is: given everything I've just laid out, have I made some horrible design mistake that has caused me to overcomplicate this class, or does it really need to be this complex?所以我的问题是:考虑到我刚刚列出的所有内容,我是否犯了一些可怕的设计错误,导致我将这个 class 过于复杂,还是真的需要这么复杂?

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 ...
            }
        }
    }
}

I fixed this by adding an explicit ReentrantLock to the Param interface.我通过向Param接口添加显式ReentrantLock来解决此问题。 So instead of using a synchronized block, I just lock the param, and let the client unlock it if he wants to.因此,我没有使用同步块,而是锁定了参数,并让客户根据需要解锁它。

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

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