We know that an object can have a synchronized method or other form of locking mechanism to prevent other threads from accessing the object when the mutex is not released. And we know that the thread is going to become blocked (hang), so there are times when a deadlock occurs: a task waiting for another task, and the other waiting for other tasks, so keep going, knowing that the task under the chain is waiting for the first task to release the lock, This creates a continuous cycle of waiting between tasks, and there is no case where the task can continue. The biggest problem with deadlocks is that it happens very little, not when we run the program and it's locked, but we don't know when the program is deadlocked and it's hard to reproduce the deadlock. In this blog we are just from the philosopher's dining problem in the process of feeling the deadlock phenomenon, random combination of analysis under the conditions of the deadlock, will not discuss how to avoid/solve the deadlock problem.
The question of dining philosophers is a classic question about deadlocks, presumably described as: there are five philosophers who spend part of their time thinking and spending part of their time eating. When they think about it, they don't need to share any complementary effects of resources. When they eat, because there are only five chopsticks, in the case of each of them need two chopsticks, will form a competition for chopsticks. The question is not to say that there will be a deadlock, just the possibility. The following code demonstrates this problem, and there are explanations for more details in the comments:
PackageIO;ImportJava.util.Random;ImportJava.util.concurrent.ExecutorService;ImportJava.util.concurrent.Executors;ImportJava.util.concurrent.TimeUnit;/** * To observe the generation of deadlocks by simulating a philosopher's question * The following code is the classic philosopher's question of simulating five philosophers and five chopsticks * *///Shared resources: Chopsticks classClass chopstick{Private Booleantoken=false;//Whether the chopsticks have been used //using chopsticks, if the chopstick has been used by another thread, then the current thread calls wait () pending Public synchronized void Take()throwsinterruptedexception{ while(token) {Wait (); } token=true; }//When the chopsticks are used, put down the chopsticks and wake up other threads that are waiting () Public synchronized void Drop() {token=false; Notifyall (); }}class Philosopers implements runnable{//left and right chopsticks PrivateChopstick left;PrivateChopstick right;Private Final intId//Philosopher use chopsticks number Private Final intPausefactor;//Pause factor PrivateRandom Rand =NewRandom ( $); Public philosopers(Chopstick Left,chopstick Right,intIdintPausefactor) { This. Left=left; This. right=right; This. Id=id; This. Pausefactor=pausefactor; }//Pause random time Private void Pause()throwsinterruptedexception{TimeUnit.MILLISECONDS.sleep (Pausefactor*rand.nextint ( -)); } Public void Run(){Try{ while(! Thread.interrupted ()) {System.out.println ( This+" "+"thinking ....." ");//Indicate being thinkingPause ();//Analog Think TimeSystem.out.println ( This+"Get the chopsticks on the left."); Left.take ();//Get the chopsticks on the leftSystem.out.println ( This+"Get the chopsticks on the right."); Right.take (); System.out.println ( This+"The Eating of the ...");//DiningPause ();//Simulated dining hours //Put down chopsticksLeft.drop (); Right.drop (); } }Catch(Interruptedexception ex) {System.out.println ( This+"Exit by interrupting exception"); } } PublicStringtoString(){return(id+1)+"Philosopher of the number"; }} Public class test { Public Static void Main(string[] args)throwsexception{//You can adjust the time of the philosopher's thinking by adjusting the Pausefactor //The shorter the thinking time, the greater the competition between threads for shared resources is more prone to deadlock problems //PAUSEFACOTR equals 0, you can see the deadlock problem almost every time . intPausefactor=0;intSize=5; chopstick[] Chopstick =NewChopstick[size];//Five chopsticks for(intI=0; i<size;i++) {Chopstick[i] =NewChopstick (); } executorservice exec = Executors.newcachedthreadpool ();//Generate 5 philosopher Threads for(intI=0; i<size; i++) {Exec.execute (NewPhilosopers (chopstick[i],chopstick[(i+1) (%size],i,pausefactor));/*//The following code prevents the generation of deadlocks by preventing cyclic waits//Let the first four philosophers always take the chopsticks on the left first, then take the chopsticks on the right, and let the fifth philosopher take the chopsticks on the right first//so as to break the conditions of the cyclic waiting, in fact this time the fifth philosopher Will always be blocked by the right chopsticks//(its right chopsticks have been taken by the first philosopher), so it will not go to the left of the chopsticks, so//fourth philosopher can always get two chopsticks first meal, thus will not produce the result of cyclic waiting (from the output can be seen To this point). if (i< (size-1)) {Exec.execute (New Philosopers (chopstick[i],chopstick[(i+1)%size],i,pausefactor)); } else{Exec.execute (New Philosopers (chopstick[(i+1)%size],chopstick[i],i,pausefactor)); } */} exec.shutdown (); System.out.println ("Press ' Enter ' to quit"); System.in.read (); Exec.shutdownnow (); }}
In the above program we can set the Philosopher's thinking time and meal time is a random time, and we can adjust it through the pausefactor, set this value several times and then run the program will find that when the value of Pausefactor is smaller, the probability of deadlock is larger , almost every time a deadlock occurs when the Pausefactor is 0, the philosopher does not take the time to think and always steals the chopsticks. This means that the more competitive the resources are, the more likely deadlocks are to occur.
Learn the operating system are aware of the need to have a deadlock four conditions to meet, we will combine the above problems to analyze the following four conditions:
1). Mutex. At least one of the resources used by a thread is not shared. Here, a chopstick can only be used by one philosopher at a time.
2). At least one task it must hold a resource and is waiting to acquire a resource that is currently held by another task. In other words, to have a deadlock, philosopher must hold a chopstick and is waiting for another root.
3). Resources cannot be preempted by tasks, and tasks must treat releasing resources as ordinary events. In the above philosopher will not rob other philosopher hands of chopstick.
4). There must be a loop waiting, when a task waits for the resources held by another task, and the latter waits for the resource held by the other task, so that it continues until a task waits for the resources held by the first task. In the code above, each philosopher will try to get the left chopstick and then get the chopstick on the right, thus creating a cyclic wait.
Deadlocks must meet the above four conditions, so the way to avoid deadlocks is to destroy one of the four conditions. There's a commented-out code that has the effect of destroying the fourth cyclic wait condition by adjusting the order in which the last philosopher acquires the chopstick (as opposed to other philosophers), thus preventing the deadlock from being generated. Other methods of preventing deadlocks are not discussed here. Java does not have a language level to prevent deadlocks, so to prevent the creation of deadlocks, only by our own cautious.
Thking in Java---Look dead lock phenomenon from the question of dining philosophers