我的疑问涉及同步使用相同方法的不同类的线程的方法。我有两个不同的类,ClientA
和ClientB
(显然扩展了Thread)和Server类的方法。 ClassA
和ClassB
的主题都必须使用此方法,但是有关于访问的不同政策:
ClassA
的线程正在使用方法内的资源,则同一类的其他线程可以使用它; ClassB
的帖子正在使用该方法,则任何人(ClassA
和ClassB
的主题都可以)使用它(互斥)。所以这是我的问题:如何应用这种同步策略?我在方法的开头使用了一个信号量(mutex),但我不确定这个解决方案,因为我认为这会每次都阻塞每种类型的线程。
答案 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 {}