【问题标题】:Fair vs NonFair公平与不公平
【发布时间】:2012-12-04 19:35:22
【问题描述】:

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

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

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

act 在哪里

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

    }

Think 并不有趣,它只是睡了一段时间。这里是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 ReentrantLock(true))和不公平(new ReentrantLock())纪律并没有太大区别。

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

公平锁定:

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

我预计不公平锁定会导致饥饿,我的意思是一些哲学家/哲学家的 eatCount 比其他人大得多,但饥饿并没有发生。为什么?

【问题讨论】:

  • 你能发布你的整个代码吗?
  • 我认为这个问题反映了对并发问题的深刻误解。它们不会一直发生,即使在有并发错误的程序中也是如此;它们只发生在周六凌晨 3 点,或者最糟糕的时候。
  • 你不仅饿死了,还可能出现死锁——毕竟抓住左叉。还有,路易斯说的。
  • @zch 不知道你为什么认为它会死锁。如果一个线程不能同时获得两个锁,它会释放已获得的锁(如果有的话)。
  • 抱歉,我错过了主动等待(通常是坏主意)部分。所以这不是僵局,但哲学家们仍然有可能保留左叉子,将它们放在桌子上的时间太短,以至于其他人都无法触及它们。所以你还有饥饿感。

标签: java multithreading


【解决方案1】:

释放锁的线程有更好的机会重新获得锁,因为它很忙,而其他线程可能被阻塞。忙等待不会显示这一点,因为每个线程都有相同的机会获取锁。可能释放锁的那个可能处于轻微的劣势。

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

但如果我用 true 使锁公平,我会看到

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 2020-12-05
        • 2018-05-31
        • 1970-01-01
        • 2018-05-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-25
        相关资源
        最近更新 更多