Java, using Locks, with research and reading list
Note: like purported "Solutions" there is some test fragility, which I\'m not sure is due to tests designed improperly, or if there is a way to correct a flaw i
Note: like purported "Solutions" there is some test fragility, which I\'m not sure is due to tests designed improperly, or if there is a way to correct a flaw in my implementation.\n\n```\n/**\n* References: \n* 1. Silberschatz, Abraham et al. "Operating Systems Concepts" 9th ed. https://learning.oreilly.com/library/view/operating-system-concepts/9781118063330/12_chapter05.html\n* 2. Goetz, Brian; Lea, Doug; Bloch, Joshua, et al. "Java Concurrency in Practice" https://learning.oreilly.com/library/view/java-concurrency-in/0321349601/ch10.html\n* 3. Lea, Doug and JSR-166 working group. JDK documentation for \njava.util.concurrent.locks.ReentrantLock https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/concurrent/locks/ReentrantLock.html\n* 4. Shavit, Nir et al. \npublisher logoThe Art of Multiprocessor Programming, Revised Reprint \n* 5. @Megaphi https://leetcode.com/problems/the-dining-philosophers/discuss/1137926/Fix-to-something-that-I\'ve-seen-a-few-people-miss\n* 6. @maximpestryakov https://leetcode.com/problems/the-dining-philosophers/discuss/745086/This-is-not-a-good-problem\n*/\n\n\nclass DiningPhilosophers {\n    List<Lock> forks = new ArrayList<>();\n    \n    /** from [3] When set fair=true, under\n     * contention, locks favor granting access to the longest-waiting\n     * thread.  Oddly, this seems to trigger a higher frequency of test fragility, but \n     * a few faster test.\n     */\n    final isFairLock = true;\n    \n    public DiningPhilosophers() {\n        for(int i=0;i<5;i++){\n            forks.add(new ReentrantLock(isFairLock));\n        }\n    }\n    /** Silberschatz [1] notes that Busy Waiting (Spinlocks)\n    * wastes CPU cycles that could be used more productive processes.  However, sleeping and\n    * waking trigger a context switch which is expensive.  Thus, spinlocks are optimal when the \n    * expected wait time is short.  The Linux kernel employs a mechanism that starts a busywait\n    * then gives up the thread, which I attempt here.\n    */\n    final int maxBusyTrials = 10;\n\n    /*\n    * It seems the "correct" solution is to put the whole execution in a synchronized block, \n    * which leetcode allows to pass, see maximpestryakov [6].  The problem is that won\'t pass\n    * an actual job interview because you\'ve forced the code to run as a sequential problem.\n    * Most leetcode discussion that employ fine grained parallelism don\'t pass 100% of the \n    * time.  Comments appreciated.\n    */\n    public void wantsToEat(int philosopher,\n                           Runnable pickLeftFork,\n                           Runnable pickRightFork,\n                           Runnable eat,\n                           Runnable putLeftFork,\n                           Runnable putRightFork) throws InterruptedException {\n        Lock left,right;\n\n        /** Regarding the if(philosopher == 4) block...\n        * [5] I remember getting this wrong in college.  Thanks @MegaPhi.\n        * The key point is to have an absolute ordering in choosing possibly contended\n        * forks.  In this case, the last philosopher picks up the fork to his right fork\n        * with his left hand.  That way, the lowest number is always the first, and we can\n        * avoid deadlocks. [2] discusses this more detail.\n        */\n        if(philosopher == 4){\n            left = forks.get(0);\n            right = forks.get(4);            \n        }else{\n            left = forks.get(philosopher);\n            right = forks.get(philosopher + 1);\n        }\n        int attempts=0;\n        while(true){\n            /**\n            * [4] FifoReadWriteLock made me look into Lock and the Condition JVM frameworks\n            */\n            if(left.tryLock()){\n                try{\n                    if(right.tryLock()){\n                        try{\n                            pickLeftFork.run();\n                            pickRightFork.run();\n                            eat.run();\n                            putRightFork.run();\n                            putLeftFork.run();\n                            return;\n                        }finally{\n                            right.unlock();\n                        }\n                    }\n                }finally{\n                    left.unlock();\n                }\n            }\n            if(attempts++ > maxBusyTrials){\n                attempts=0;\n                try{\n                    /** \n                    * Other leetcode solutions call Thread.sleep.  I was hoping to use\n                    * wait() and notifyAll() but I haven\'t gotten the synchronized block\n                    * to behave with this business logic yet. Will post, comments appreciated.\n                    */\n                    Thread.sleep(1);\n                }catch(InterruptedException e){}\n            }\n        }\n    }\n}\n```
[]