[Java with explanation] locking solution with resource ordering
Explanations first:\n1. This solution avoids deadlock by numbering resources, and have threads acquire the respective mutexes in ascending order, but release th
Explanations first:\n1. This solution avoids deadlock by numbering resources, and have threads acquire the respective mutexes in ascending order, but release them in descending order. This is a general way of preventing deadlocks, and is applicable in many more cases of resource contention.\nSpecifically in this problem, philosophers 0-3 will pick up their left forks first, but philosopher 4 will pick up their right fork first. If we number the forks 0-4 with the one to the left of philosopher 0 as number 0, philosopher 4 will need to pick up fork 0, then fork 4.\nThus, the closest scenario to deadlocking would be, philosophers 0-3 hold their left forks, but philosopher 4 is unable to pick up their right fork (because it\'s fork 0, which is held by philosopher 0), and will not subsequently pick up their left fork (fork 4). The scenario will then unwind with philosopher 3 picking up their right fork (fork 4), eating, and putting both forks down, enabling philosophers 2-0 to eat in order.\n2. It\'s also OK to use semaphores with capacities of 1, they are equivalent to locks. The locks also don\'t need to be reentrant, because each thread will acquire the same lock only once.\n3. Notice the releasing of locks are in descending order (i.e. reverse of the order of acquiring), which is also needed to prevent deadlocking.\n\nCode:\n```\nimport java.util.concurrent.locks.ReentrantLock;\n\nclass DiningPhilosophers {\n    private ReentrantLock[] mutexes;\n\n    public DiningPhilosophers() {\n        this.mutexes = new ReentrantLock[5];\n        for (var i = 0; i < 5; i ++) {\n            this.mutexes[i] = new ReentrantLock();\n        }\n    }\n\n    // call the run() method of any runnable to execute its code\n    public void wantsToEat(\n        int philosopher, Runnable pickLeftFork, Runnable pickRightFork, Runnable eat, Runnable putLeftFork, Runnable putRightFork\n    ) throws InterruptedException {\n        var forkNumbers = new int[] {philosopher, (philosopher + 1) % 5};\n        Arrays.sort(forkNumbers);\n        \n        this.mutexes[forkNumbers[0]].lock();\n        this.mutexes[forkNumbers[1]].lock();\n        eat(pickLeftFork, pickRightFork, eat, putRightFork, putLeftFork);\n        this.mutexes[forkNumbers[1]].unlock();\n        this.mutexes[forkNumbers[0]].unlock();\n    }\n\n    private void eat(Runnable ... actions) {\n        for (var action : actions) {\n            action.run();\n        }\n    }\n}\n```
[]