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

时间:2017-05-10 22:45:54

标签: java multithreading mutex semaphore

我的疑问涉及同步使用相同方法的不同类的线程的方法。我有两个不同的类,ClientAClientB(显然扩展了Thread)和Server类的方法。 ClassAClassB的主题都必须使用此方法,但是有关于访问的不同政策:

  • 如果ClassA的线程正在使用方法内的资源,则同一类的其他线程可以使用它;
  • 如果ClassB的帖子正在使用该方法,则任何人(ClassAClassB的主题都可以)使用它(互斥)。

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

2 个答案:

答案 0 :(得分: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 

答案 1 :(得分: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 {}