首页 文章

如何在同一方法上同步不同类的线程

提问于
浏览
0

我怀疑是如何同步使用相同方法的不同类的线程 . 我有两个不同的类, ClientAClientB (显然扩展了Thread)和一个Server类的方法 . ClassAClassB 的线程都必须使用此方法,但是有关于访问的不同策略:

  • 如果 ClassA 的线程正在使用方法内的资源,则同一类的其他线程可以使用它;

  • 如果 ClassB 的线程正在使用该方法,则nobody( ClassAClassB 的线程)都可以使用它(互斥) .

所以这是我的问题:如何应用这种同步策略?我在方法的开头使用了一个信号量(互斥量),但我不确定这个解决方案,因为我认为每次都会阻塞每种类型的线程 .

2 回答

  • 0

    我认为你可以使用java.util.concurrent.locks.ReentrantLock来实现这一点 .

    示例略有不同 . ClientA让所有人都进入,ClientB不会:

    private final ReentrantLock lock = new ReentrantLock();
        private void method(boolean exclusive){
            log.debug("Before lock() ");
                try {
                    lock.lock();
                    if (!exclusive) {
                        lock.unlock();
                    }
    
                    log.debug("Locked part");
                    //Method tasks....
                    Thread.sleep(1000);
                }catch(Exception e){
                    log.error("",e);
                }finally {
                    if(exclusive)
                        lock.unlock();
                }
             log.debug("End ");
        }
    

    执行:

    new Thread("no-exclusive1"){
        @Override
        public void run() {
            method(false);
        }
    }.start();
    new Thread("exclusive1"){
        @Override
        public void run() {
            method(true);
        }
    }.start();
    new Thread("exclusive2"){
        @Override
        public void run() {
            method(true);
        }
    }.start();
    new Thread("no-exclusive2"){
        @Override
        public void run() {
            method(false);
        }
    }.start();
    

    结果:

    01:34:32,566 DEBUG (no-exclusive1) Before lock() 
    01:34:32,566 DEBUG (no-exclusive1) Locked part
    01:34:32,566 DEBUG (exclusive1) Before lock() 
    01:34:32,566 DEBUG (exclusive1) Locked part
    01:34:32,567 DEBUG (exclusive2) Before lock() 
    01:34:32,567 DEBUG (no-exclusive2) Before lock() 
    01:34:33,566 DEBUG (no-exclusive1) End 
    01:34:33,567 DEBUG (exclusive1) End 
    01:34:33,567 DEBUG (exclusive2) Locked part
    01:34:34,567 DEBUG (exclusive2) End 
    01:34:34,567 DEBUG (no-exclusive2) Locked part
    01:34:35,567 DEBUG (no-exclusive2) End
    
  • 0

    也许有点复杂,但我仍然认为如何使用同步块来演示如何考虑它会很有趣:

    public class Server() {
    
        private LinkedList<Object> lockQueue = new LinkedList<Object>();
    
        public void methodWithMultipleAccessPolicies(Object client) {
            Object clientLock = null;
    
            // These aren't really lock objects so much as they are
            // the targets for synchronize blocks.  Get a different
            // type depending on the type of the client.
            if (client instanceof ClientA) {
                clientLock = new ALock();
            } else {
                clientLock = new BLock();
            }
    
            // Synchronize on the "lock" created for the current client.
            // This will never block the current client, only those that
            // get to the next synchronized block afterwards.
            synchronized(clientLock) {
                List<Object> locks = null;
    
                // Add it to the end of the queue of "lock" objects.
                pushLock(clientLock);
    
                // Instances of ClientA wait for all instances of
                // ClientB already in the queue to finish.  Instances
                // of ClientB wait for all clients ahead of them to
                // finish.
                if (client instanceof ClientA) {
                    locks = getBLocks();
                } else {
                    locks = getAllLocks();
                }
                // Where the waiting occurs.
                for (Lock lock : locks) {
                    synchronized(lock) {}
                }
    
                // Do the work.  Instances of ClientB should have
                // exclusive access at this point as any other clients
                // added to the lockQueue afterwards will be blocked
                // at the for loop.  Instances of ClientA should
                // have shared access as they would only be blocked
                // by instances of ClientB ahead of them.
                methodThatDoesTheWork();
    
                // Remove the "lock" from the queue.
                popLock(clientLock);
            }
        }
    
        public void methodThatDoesTheWork() {
            // Do something.
        }
    
        private synchronized void pushLock(Object lock) {
            lockQueue.addLast(lock);
        }
    
        private synchronized void popLock(Object lock) {
            lockQueue.remove(lock);
        }
    
        private synchronized List<Object> getAllLocks() {
            return new ArrayList<Object>(lockQueue);
        }
    
        private synchronized List<Object> getBLocks() {
            ArrayList<Object> bLocks = new ArrayList<>();
            for (Object lock : lockQueue) {
                if (lock instanceof BLock) {
                    bLocks.add(lock);
                }
            }
        }
    }
    
    public class ALock {}
    public class BLock {}
    

相关问题