当前位置: 首页 > 知识库问答 >
问题:

信号量公平性参数不遵循先进先出

益光亮
2023-03-14

我正在开发一个简单的信号量程序,其中我正在初始化一个计数为4的信号量,并启动6个线程。在run方法中,我获取信号量锁,在每个线程完成后,我释放锁。

这是我的代码:

import java.util.concurrent.Semaphore;

public class SemaphoreTest {
    
    static Semaphore semaphore = new Semaphore(4, true);
    
    static class MyThread extends Thread{
        
        String  name = "";
        
        public MyThread(String name){
            this.name = name;
            
        }
        
        public void run(){
            
            System.out.println(name+" going to acquire lock...");
            System.out.println("Available Permits = "+semaphore.availablePermits());
            
            try {
                semaphore.acquire();
                System.out.println(name+" got permit.");
                
                try{
                    for(int i=1;i<=1;i++){
                        System.out.println(name+" is performing operation "+i+". Available Semaphore permits are : "+semaphore.availablePermits());
                        Thread.sleep(1000);
                    }
                        
                }finally{
                    System.out.println(name+" Releasing lock...");
                    semaphore.release();
                    System.out.println("Available permits after releasing "+"name"+" = "+semaphore.availablePermits());
                }
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            
            
        }
    }
    
    public static void main(String[] args){
        Thread t1 = new MyThread("A");
        t1.start();
        
        Thread t2 = new MyThread("B");
        t2.start();
        
        Thread t3 = new MyThread("C");
        t3.start();
        
        Thread t4 = new MyThread("D");
        t4.start();
        
        Thread t5 = new MyThread("E");
        t5.start();
        
        Thread t6 = new MyThread("F");
        t6.start();
    }

}

结果如下:

A going to acquire lock...
Available Permits = 4
C going to acquire lock...
A got permit.
A is performing operation 1. Available Semaphore permits are : 3
B going to acquire lock...
Available Permits = 3
B got permit.
F going to acquire lock...
E going to acquire lock...
Available Permits = 2
Available Permits = 3
D going to acquire lock...
Available Permits = 0
C got permit.
C is performing operation 1. Available Semaphore permits are : 0
E got permit.
E is performing operation 1. Available Semaphore permits are : 0
Available Permits = 2
B is performing operation 1. Available Semaphore permits are : 2
A Releasing lock...
E Releasing lock...
Available permits after releasing name = 2
D got permit.
D is performing operation 1. Available Semaphore permits are : 1
B Releasing lock...
C Releasing lock...
Available permits after releasing name = 1
F got permit.
F is performing operation 1. Available Semaphore permits are : 2
Available permits after releasing name = 2
Available permits after releasing name = 2
D Releasing lock...
F Releasing lock...
Available permits after releasing name = 3
Available permits after releasing name = 4

现在,从java文档开始:

java.util.concurrent.信号量。信号量(int许可,布尔公平)

使用给定的许可数量和给定的公平性设置创建信号量。

参数:
允许可用许可的初始数量。此值可能为负值,在这种情况下,必须在授予任何获取之前发布。
如果此信号量将保证在争用情况下先进先出地授予许可,则为true,否则为false

构造函数信号量(int-allows,boolean-fair)保证先进先出。但就这个程序的输出而言,它是不一样的。锁的获取如下:

A-

锁按如下方式释放:

A-

请建议是否符合预期?还是我遗漏了什么?


共有2个答案

严令秋
2023-03-14

这里有一个关于线程计时的误解:假设线程一输出消息就会获得锁,但事实上,没有理由不在这两者之间暂停线程。

C: System.out.println(...);
C: thread gets put on hold
A: System.out.println(...);
A: aquires lock
B: System.out.println(...);
B: aquires lock
C: resumes
C: aquires lock
郎魁
2023-03-14
匿名用户

释放许可证的顺序只是run方法花费的时间的结果,与公平无关。

这里的FIFO意味着如果两个线程调用信号量。acquire()并且没有可用的许可证,当有许可证可用时,首先调用它的线程将是第一个接收许可证的线程。

在您的示例中,A、B、C、E获取许可证是因为它们首先调用acquire,而D和F必须等待许可证可用。然后,似乎D在F之前调用了acquire,因此获得了第一个可用的许可证。

 类似资料:
  • 我试图理解这个旧考试任务的答案,在这个任务中,学生应该使用JavasReentrantLock实现一个公平的二进制信号量。我不明白这些计数器的意义: 它在任务的描述中说,“你可以假设程序中使用信号量最多有20个线程。此外,最多1000万信号量操作将在程序的一次运行中执行。"在任务的解决方案中,它说:“每个试图获取信号量的线程必须在队列中注册自己,并且只有在之前的线程离开队列后才离开队列。每个线程使

  • 王军霞跑得快,能得奥运会冠军,人家跑步是有技术的。动不动就一万几千米地跑你就要学会前紧后松,要是一上来就百米冲刺般跑出去,前面倒是能领先好一阵,可好景不长,最后不要说拿第一名,连名次都没有就可惜了,毕竟你还为了这事还花去了好大体力。 但牛人也例外,记得绝影还是年大学的时候,有一次体育考一千米跑,几个人跑下来累得像猪一样,却发现旁边有个不认识的猛男一直保持着冲刺的速度。一干女生无不羡慕地说:“你看人

  • 我正在研究一种算法,在该算法中,我希望在从该优先级队列中删除元素时,保持优先级队列中具有相同优先级的元素的FIFO顺序。 虽然,我已经看到了将自动递增的序列号作为辅助键的解决方案,并使用它来打破联系,但我需要类似的链接,但我面临的问题是,我想要比较的元素-TestItemChange(下面示例中的类)没有实现Compariable,我无法(也不想)修改它以使其实现。所以现在,在优先级队列中没有FI

  • 问题内容: 在此代码中: 我所期望的 由于最里面的括号的优先级,将执行First 。因此,值将为11,此表达式的值将为15。然后将被执行。所以12 * 15 =180。所以z = 180 我得到了什么 z = 176 这意味着VM从左到右不遵循操作员优先级。那么我对运算符优先级的理解是错误的吗? 问题答案: 表达式( y *(y + 5)); 将被放置在这样的堆栈中: 结果将按照该顺序执行 该表达

  • 介绍 FIFO(first in first out) 先进先出策略。元素不停的加入缓存直到缓存满为止,当缓存满时,清理过期缓存对象,清理后依旧满则删除先入的缓存(链表首部对象)。 优点:简单快速 缺点:不灵活,不能保证最常用的对象总是被保留 使用 Cache<String,String> fifoCache = CacheUtil.newFIFOCache(3); //加入元素,每个元素可以设

  • 我有多个进程与Sempahore同步。我知道这段代码不允许gurantee出现这样的情况:在sem_getvalue期间,即使值变为零,甚至在调用特定进程中的sem_post之前,anotehr进程也可能调用sem_post,使值变为2。如何解决这种情况。 我的问题不能通过互斥体来解决,在我的问题中,有些进程只用于信号,即操作,而在互斥体中,所有进程都将等待并不断地发出信号