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

公平vs非公平

方祺
2023-03-14

我已经通过RentrantLock接受了公平和非公平纪律的测试。我写了一个模拟哲学家吃饭的小程序

每个哲学家都有左右叉子,分别是ReentrantLocks。我模拟了1000次思考和进食行为:

 for (int i = 0; i < ACT_TIMES; i++) {
            act();
        }

act在哪里

private void act() {
        think();
        eat();

    }

想想没什么意思,只是睡了一段时间而已。下面是eat的方法

private void eat() {
        try {
            if (left.tryLock(0, TimeUnit.MILLISECONDS)) {
                if (right.tryLock(0, TimeUnit.MILLISECONDS)) {
                    log("eating");
                    eatCount++;
                    try {
                        Thread.sleep(EAT_TIME);
                    } catch (InterruptedException e) {
                    } finally {
                        left.unlock();
                        right.unlock();
                    }
                } else {
                    left.unlock();
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

主要方法:

 Lock[] forks = new Lock[5];
        for (int i = 0; i < forks.length; i++) {
            forks[i] = new ReentrantLock();
        }
        Philosopher p1 = new Philosopher(0, forks[1], forks[0]);
        Philosopher p2 = new Philosopher(1, forks[2], forks[1]);
        Philosopher p3 = new Philosopher(2, forks[3], forks[2]);
        Philosopher p4 = new Philosopher(3, forks[4], forks[3]);
        Philosopher p5 = new Philosopher(4, forks[0], forks[4]);
        ExecutorService exec = Executors.newFixedThreadPool(5);
        exec.submit(p1);
        exec.submit(p2);
        exec.submit(p3);
        exec.submit(p4);
        exec.submit(p5);

完成所有5个线程后,我为每个哲学家打印eatCount。这些值对于公平(new ReentantLock(true))和不公平(new ReentantLock())纪律没有太大差异。

(第一个数字是一个哲学家的数字)

公平锁定:

0 344
1 348
2 366
3 359
4 363
Total number of eating 1780

不公平锁定:

0 338
1 338
2 339
3 341
4 352
Total number of eating 1708

我曾预料到一些哲学家会挨饿,我的意思是有些哲学家必须比其他人吃得多,但饥饿并没有发生。为什么?


共有3个答案

卢深
2023-03-14

@Maks,你试过为EAT_TIME设置随机值吗?

这可能会给逻辑带来一些不公平。

夏朗
2023-03-14

删除所有睡眠(),你可能会看到一些不公平。

寿毅庵
2023-03-14

释放锁的线程有更好的机会重新获得锁,因为它很忙,而其他线程可能被阻塞。繁忙等待不会显示这一点,因为每个线程都有均等的机会获取锁。释放锁的那个可能有点不利。

final ReentrantLock lock = new ReentrantLock();
for (int i = 0; i < 5; i++) {
    final int finalI = i;
    new Thread(new Runnable() {
        @Override
        public void run() {
            for (int j = 0; j < 5; j++) {
                lock.lock();
                System.out.println("locked by " + finalI);
                lock.unlock();
            }
        }
    }).start();
}

印刷品

locked by 0
locked by 0
locked by 0
locked by 0
locked by 0
locked by 1
locked by 1
locked by 1
locked by 1
locked by 1
locked by 2
locked by 2
locked by 2
locked by 2
locked by 2
locked by 3
locked by 3
locked by 3
locked by 3
locked by 3
locked by 4
locked by 4
locked by 4
locked by 4
locked by 4

但是如果我让锁变得公平

locked by 0
locked by 1
locked by 2
locked by 3
locked by 4
locked by 0
locked by 1
locked by 2
locked by 3
locked by 4
locked by 0
locked by 1
locked by 2
locked by 3
locked by 4
locked by 0
locked by 1
locked by 2
locked by 3
locked by 4
locked by 0
locked by 1
locked by 2
locked by 3
locked by 4
 类似资料:
  • 本文向大家介绍ReentrantLock源码详解--公平锁、非公平锁,包括了ReentrantLock源码详解--公平锁、非公平锁的使用技巧和注意事项,需要的朋友参考一下 问题 (1)重入锁是什么? (2)ReentrantLock如何实现重入锁? (3)ReentrantLock为什么默认是非公平模式? (4)ReentrantLock除了可重入还有哪些特性? 简介 Reentrant = Re

  • 当锁被释放后,任何一个线程都有机会竞争得到锁,这样做的目的是提高效率,但缺点是可能产生线程饥饿现象。

  • 本文向大家介绍请讲一下非公平锁和公平锁在reetrantlock里的实现过程是怎样的。相关面试题,主要包含被问及请讲一下非公平锁和公平锁在reetrantlock里的实现过程是怎样的。时的应答技巧和注意事项,需要的朋友参考一下 考察点:锁 如果一个锁是公平的,那么锁的获取顺序就应该符合请求的绝对时间顺序,FIFO。对于非公平锁,只要CAS设置同步状态成功,则表示当前线程获取了锁,而公平锁还需要判断

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

  • 如何使用约束流api计算员工的公平性。 https://www.optaplanner.org/blog/2017/02/03/FormulaForMeasuringUnfairness.html 我在网球求解器示例中看到了上述流口水的实现。 https://github.com/kiegroup/optaplanner/blob/581d10fb8140f37b7491d06b2bab8d5ac

  • 在B. Goetz的Java实践中的并发,第13.5节说: 在Java5.0中,读锁的行为更像是一个信号量而不是锁,只维护活动读卡器的数量,而不是它们的身份。Java 6中的行为已更改,以跟踪哪些线程已被授予读锁6。 6这种变化的一个原因是,在java 5.0下,锁实现不能区分第一次请求读锁的线程和重入锁请求,这将使公平读写锁容易死锁。 我的问题是公平有什么问题?为什么不公平的读写锁会被死锁屏蔽?