Java 如果多个线程试图锁定,信号量的行为如何

Java 如果多个线程试图锁定,信号量的行为如何,java,multithreading,Java,Multithreading,我试图理解信号量,并且知道信号量维护一组许可证或允许数量的锁,但是我仍然有很多疑问 类的每个实例或整个类本身维护的锁的允许数量是多少 我的意思是说,当信号量按照我的代码限制为2时,为什么4个线程获得了锁 这是否意味着该类的每个实例都要维护许可证。如果是, 那么它不会在代码的状态中产生不一致性吗 运行以下代码时,输出如下: t1 having ts1 acqired lock t2 having ts2 acqired lock t3 having ts1 acqired lock t4 havi

我试图理解信号量,并且知道信号量维护一组许可证或允许数量的锁,但是我仍然有很多疑问

类的每个实例或整个类本身维护的锁的允许数量是多少

我的意思是说,当信号量按照我的代码限制为2时,为什么4个线程获得了锁

这是否意味着该类的每个实例都要维护许可证。如果是, 那么它不会在代码的状态中产生不一致性吗

运行以下代码时,输出如下:

t1 having ts1 acqired lock
t2 having ts2 acqired lock
t3 having ts1 acqired lock
t4 having ts2 acqired lock
t1 having ts1 released lock
t4 having ts2 released lock
t3 having ts1 released lock
t2 having ts2 released lock
守则:

public class SemaphoreTest {


    public static void main(String[] args) {
        Task ts1=new Task();
        Task ts2=new Task();
        Thread t1=new Thread(ts1,"t1 having ts1");
        Thread t2=new Thread(ts2,"t2 having ts2");
        Thread t3=new Thread(ts1,"t3 having ts1");
        Thread t4=new Thread(ts2,"t4 having ts2");
        t1.start();
        t3.start();
        t2.start();
        t4.start();

    }
}

class Task implements Runnable{
    Semaphore noOfLocks=new Semaphore(2);

    @Override
    public void run() {
        try {
            noOfLocks.acquire();
            System.out.println(Thread.currentThread().getName() +" acqired lock");
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally{
            noOfLocks.release();
            System.out.println(Thread.currentThread().getName() +" released lock");
        }

    }

}

任务
类的每个实例都有自己的
信号量实例

class Task implements Runnable {
    Semaphore noOfLocks=new Semaphore(2);
    ...
每个信号量实例都有自己的许可证计数器

您创建了两个
Task
实例,因此有2个
Semaphore
实例,每个实例最初有2个许可证

    Task ts1=new Task();
    Task ts2=new Task();
同时在多个线程中执行
ts1
,将导致线程争夺同一信号量。在多个线程中执行
ts2
也是如此。在您的代码中:

    Thread t1=new Thread(ts1,"t1 having ts1");
    Thread t3=new Thread(ts1,"t3 having ts1");

因此,最终有2个线程使用2个许可证中的2个乘以2。没有什么需要等待许可证,因为每个人都有足够的许可证


如果您想查看某些内容,请使用现有任务生成更多线程或减少初始许可量。

您有两个信号灯,每个信号灯允许两个锁。那是4。我看不出有什么问题。这根本不是我得到的结果。您的信号灯(其中2个)只有1个许可证。一次只能有一个线程访问每个实例。@biziclop我需要确认每个实例上是否保留了允许的锁数。因为我已经提到了2个锁并创建了2个对象,所以4个线程能够获得锁。如果两个线程在同一个对象上获得了锁,那么它们可能会试图更新同一实例变量的值,从而产生一些不一致的状态。@SotiriosDelimanolis我已根据输出更改了代码。请尝试每个信号量对象的许可数量(如您所期望的)。您创建了两个独立的任务,这两个任务又创建了各自的信号量对象(每个对象一个),很抱歉,我仍然不明白问题是什么。假设类任务中有一个hashmap的实例变量,在我的run()方法中,我是这样做的:if(!hasmap.contains(key)){hashmap.put(key,value)}ts1上的T1检查条件并输入内部If块。现在CPU从T1切换到T3,这也检查ts1上的条件,并进入If块。现在我们在IF块中有两个线程,这可能会导致T1覆盖T3值,反之亦然,这是一种不理想的情况。这是如何处理的,或者我的理解有什么差距。如果它没有被信号量处理,那么它的优势是什么?@user2800089如果你用一个正好有1个许可证的信号量来保护
If(!h…lue)}
的整个过程,它工作得很好。T3将不得不等待,因为许可证(以及对hashmap的访问)在T1修改时属于T1。具有超过1个许可证的信号量对于保护一次只能由1个线程使用的东西没有用处,因此您通常使用
synchronized
ReentrantLock
,因为它们只有1个“许可证”。信号量用于其他场景,例如,您有一个数据库连接池,并且不希望并行使用超过5个连接。非常感谢。这是我的全部问题,现在已经澄清了。请解释一下给定链接中的代码段的输出,当每个实例只声明了2个许可证时,那么为什么我可以发布4个许可证,以及可用许可证的数量是如何达到7的。@user2800089信号量不会限制您最初可用的数量许可证。您可以随意添加,也可以根据需要将其删除。你甚至不必归还你带他们去的地方。您可以编写代码,其中一个线程生成许可证,另一个线程使用许可证以获得速率受限的执行。代码中的7如下所示:您从2个许可证开始,然后2个线程获取2并添加4,这样您就得到了8(2-1+4-1+4)。然后第三条线再接一条,你就7岁了。在该线程释放另一个4之前,它会打印7。最后将有11个许可证。
    Thread t2=new Thread(ts2,"t2 having ts2");
    Thread t4=new Thread(ts2,"t4 having ts2");