首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用Java锁定框架实现餐饮哲学家的问题以避免死锁

用Java锁定框架实现餐饮哲学家的问题以避免死锁
EN

Code Review用户
提问于 2017-11-24 01:39:15
回答 1查看 1.7K关注 0票数 1

餐饮哲学家问题是计算机科学中的经典问题之一。我打算使用Java线程来实现它。我尝试使用Java5附带的锁定框架,并使用tryLock()方法来避免死锁。我的实现相当简单。我实现了runnable接口来表示哲学家,并使用executor服务来运行所有这些runnable。

作为锁,我使用了ReentrantLock。我知道这里已经讨论了几个实现,但我想了解一下我的实现。

代码语言:javascript
复制
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;

public class Philosopher implements Runnable {
    private String name;
    private final Lock leftFork;
    private final Lock rightFork;

    public Philosopher(String name, Lock leftFork, Lock rightFork) {
        this.name = name;
        this.leftFork = leftFork;
        this.rightFork = rightFork;
    }

    public void think() {
        log("thinking");
    }

    public void eat() {
        //assume, eating requires some time.
        //let's put a random number
        try {
            log("eating");
            int eatingTime = getRandomEatingTime();
            TimeUnit.NANOSECONDS.sleep(eatingTime);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }

    @Override
    public void run() {
        while (true) {
            keepThinkingAndEating();
        }
    }

    private void keepThinkingAndEating() {
        think();

        if (leftFork.tryLock()) {
            try {
                log("grabbed left fork");
                if (rightFork.tryLock()) {
                    try {
                        log("grabbed right fork");
                        eat();
                    } finally {
                        log("put down right fork");
                        rightFork.unlock();
                    }
                }
            } finally {
                log("put down left fork");
                leftFork.unlock();
            }
        }
    }

    private void log(String msg) {
        DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_TIME;
        String time = formatter.format(LocalDateTime.now());
        String thread = Thread.currentThread().getName();
        System.out.printf("%12s %s %s: %s%n", time, thread, name, msg);
        System.out.flush();
    }

    private int getRandomEatingTime() {
        Random random = new Random();
        return random.nextInt(500) + 50;
    }
}

以及运行此代码的主要方法:

代码语言:javascript
复制
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class PhilosopherMain {
    public static void main(String[] args) {
        Lock[] forks = new Lock[5];
        for (int i = 0; i < forks.length; i++) {
            forks[i] = new ReentrantLock();
        }

        Philosopher[] philosophers = new Philosopher[5];

        ExecutorService executorService = Executors.newFixedThreadPool(5);

        for (int i = 0; i < philosophers.length; i++) {
            Lock leftFork = forks[i];
            Lock rightFork = forks[(i + 1) % forks.length];
            philosophers[i] = new Philosopher("Philosopher " + (i + 1), leftFork, rightFork);
            executorService.execute(philosophers[i]);
        }

        executorService.shutdown();
    }
}
EN

回答 1

Code Review用户

回答已采纳

发布于 2017-11-24 09:09:06

您的实现是极简式的,但它做的是它所做的,并且它做得很好。

您的代码主要由三个元素组成:

  1. 设置位置
  2. 伐木哲学家的行为
  3. 处理哲学家行为

1和2并不那么有趣,因为它们可能因实现而略有不同。一般来说,您没有达到一个代码质量来解决任何模块化问题。

第三部分是我想说的。你选择了餐饮哲学家的利己主义变体。如果其他哲学家继续在不利的时刻采取分叉,哲学家可能会面临饥饿。

另一个变体是合作的。你得再介绍一件艺术品才行。哲学家可以直接给他们的邻居,如果他们登记使用叉子,而叉子本身目前是无效的。这使哲学家不能立即松开叉子并再次询问,因此其他哲学家没有机会在此过程中自我介绍。

票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/181188

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档