问题描述
从我读到的理论来看,有两种类型
1) Binary :-0或1作为值,或者换句话说,只有一个线程允许进入关键部分(或者我可能没有正确解释它)
2)计数:-仅允许n个线程中的k个访问k个资源[k =资源数量,n =线程数量始终为n> k]
- 为什么要使用二进制信号量?
如果是二进制信号量,即
Semaphore sem = new Semaphore(1);
用于只允许一个thead进入的地方,它们是否与任何普通的LOCK都做同样的事情?即只允许一个线程进入内部,然后如何进入
sem.aquire(); //since count=1 only one thread enters
try
{
//Important Stuff which can be accessed only by one thread
}
finally{sem.release();}
有什么不同吗?
lock.lock()
try
{
//Again only one thread allowed here same as binary semaphore
}
finally{lock.unlock();}
- 为什么要计数信号量?
现在让我们说有
a)3个资源R1,R2,R3和一个资源一次只能由1个线程使用
b)9个线程T1,T2 ..... T9
c)这是每个线程如何使用这些资源
-> T1,T2,T3 =>想要R1
-> T4,T5,T6 =>想要R2
-> T5,T6,T7 =>想要R3
一个人会说,对信号量进行计数将只允许3个线程最多获取3个资源,如果每个线程都试图获取一个唯一的资源,这将很好地工作,但显然在此示例中情况并非如此。可以说,如果T1,T2,T3都进入了关键部分,那么T1得到R1,并且R1现在已从可用资源列表中删除。现在T2,T3将崩溃,因为R1现在不可用。
您可以锁定资源的每种方法,而不是将其从资源队列中删除,以确保是否共享一个资源,只有一个线程可以使用它,但这不仅破坏了信号量的目的,而且现在我们同时具有信号灯和锁的开销。
信号量如何解决N个线程访问1个资源的问题,即N-> k,其中k是k1,k2,k3 ... kn个资源队列中的资源?
我的解决方案
并不完美,但不需要锁并且很公平
private final class Resource
{
private static final HashMap<Integer,Resource> instances=new HashMap(); //An map keeping track of available resources
private static final Object aquireLock=new Object(); //allow only one thread to aquire an resource and add itself to the waiting queue if it was not available at a time
private static final ArrayList<QueueObject> waiting=new ArrayList();//list of threads waiting to aquire an resource
private static void init() //Only 3 resources
{
instances.put(0,new Resource());
instances.put(1,new Resource());
instances.put(2,new Resource());
}
private static void use(int index,Consumer<Resource> action)
{
Resource res=null;
boolean doWait=false;
synchronized(aquireLock)
{
if(instances.containsKey(index)){res=instances.remove(index);}//remove resource to make it unavailable
else{doWait=true;}//not available? then wait
}
if(doWait)
{
QueueObject wait=new QueueObject(index); //store the name[index] of the resource it was asking so it can be woken up when that resource is available
synchronized(waiting){waiting.add(wait);} //Now wait in queue
wait.doWait();
waiting.remove(wait);//wait over remove itself from queue
}
if(res==null){res=instances.remove(index);}//after wait again try to get resource[if it already has resource res wont be null]
try{action.accept(res);}//do stuff with resource
finally
{
synchronized(aquireLock){instances.put(index,res);}//Resource utilized Now return it back to the queue
synchronized(waiting)
{
waiting.stream()
.filter(obj->obj.resID==index) //find the 1st thread in queue that was asking for this resource and wake it up so it can use it Now
.findFirst()
.ifPresent(QueueObject::doNotify);
}
}
}
private static final class QueueObject
{
private boolean isNotified = false;
private final int resID;
private QueueObject(int resID){this.resID=resID;}
private synchronized void doWait()
{
while(!isNotified) //protection against missed signals and spurIoUs wake up's
{
try{this.wait();}
catch(InterruptedException ex){}
}
this.isNotified = false;
}
private synchronized void doNotify()
{
this.isNotified = true;
this.notify();
}
}
}
因此,使用二进制信号量执行相同的操作时,将锁定并计数信号量,该问题具有保护1个资源(在k个资源的队列中)免受N个线程影响的问题?
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)