Java multi-thread producer consumer problem <一> : Using synchronized keyword to solve producer consumer problems __java

Source: Internet
Author: User

Today I read a blog about the collaboration of Java multi-line threads, the author of the program to illustrate the issue of producers and consumers, but I and other readers found that the program more than a few times or there will be deadlocks, Baidu searched the majority of examples are also a bug, after careful study found that the problem, and resolved, Feel a sense of meaning posted out to share.

The first post is the bug code, a 4-class, Plate.java:

Package Creatorandconsumer;

Import java.util.ArrayList;
Import java.util.List;

/**
 * Plate, indicating shared resources
 * @author Martin * * */Public
class Plate {
	private list<object> eggs = New Arraylist<object> ();
	
	/**
	 * Get egg
	 * @return
	/Public Object Getegg ()
	{
		System.out.println ("Consumers take Eggs");
		Object egg = eggs.get (0);
		Eggs.remove (0);
		return egg;
	}
	
	
	/**
	 * Add Egg * @return * * * public
	void Addegg (Object egg)
	{
		System.out.println ("producer Egg");
		Eggs.add (egg);
	}
	
	/**
	 * Get the number of eggs
	 * @return
	 /public
	int Geteggnum ()
	{return
		eggs.size ();
	}
}
Consumer class: Consumer2.java

Package Creatorandconsumer;

public class Consumer2 implements Runnable {
	/**
	 * Thread Resource * *
	private Plate Plate;

	Public Consumer2 (Plate Plate) {
		this.plate = Plate;
	}

	@Override public
	Void Run () {
		synchronized (plate) {
			//If the number of eggs is greater than 0 at this time, wait while
			(Plate.geteggnum ()) < 1 {try {///
					This detail requires that if the thread enters a wait, the lock on it is temporarily released,/
					/Otherwise the other thread cannot lock it, and then wakes this thread
					plate.wait ();
				} catch (Interruptedexception e) {
					e.printstacktrace ();
				}
			}

			Wake up, the resource lock again, and the conditions can be assured to take the eggs
			Plate.getegg ();
			Plate.notify ();}}


Producer Category: Creator2.java

Package Creatorandconsumer;

/** *
 producer
 * * 
 @author Martin */Public
class Creator2 implements Runnable {
	/**
	 * Thread Resources
	 * *
	private Plate Plate;

	Public Creator2 (Plate Plate) {
		this.plate = Plate;
	}

	@Override public
	Void Run () {
		synchronized (plate) {
			//If the number of eggs is greater than 0 at this time, wait while
			(Plate.geteggnum ())  >= 5) {
				try {///
					This detail requires that if the thread enters a wait, the lock on it is temporarily released,/
					/Otherwise the other thread cannot lock it, and then wakes this thread
					plate.wait ();
				} catch (Interruptedexception e) {
					e.printstacktrace ();
				}
			}

			After awakening, the resource lock is obtained again, and the condition can be satisfied with the eggs.
			Object egg = new Object ();
			Plate.addegg (egg);
			Plate.notify ();}}


Test class: Tester.java

Package Creatorandconsumer;

public class Tester {public
	static void Main (string[] args)
	{
		//shared resource
		Plate Plate = new Plate ();
		
		Add producer and consumer for
		(int i = 0; i < i + +)
		{
			//There is bug version
			new Thread (New CREATOR2 (plate)). Start ();
			New Thread (New CONSUMER2 (plate)). Start ();
			
			No bug version
			//new Thread (new Creator (plate)). Start ();
			New Thread (New Consumer (plate)). Start ();


If you run a few more times or you change the number of loops in your test class, you'll find that the probability of a deadlock is high. The following is an analysis of why this problem occurs:

There is an explanation for object.wait in the JDK that the current thread must have this object monitor. The thread discards ownership of this monitor and waits until another thread wakes up by calling the Notify method, or by notifyall the thread waiting on the monitor on this object. Can be seen below a situation may appear: Consumer 1 into the waiting state (at this time the resource lock has been released), if the consumer 2 access to the resource synchronization lock (no one to ensure that consumers 1 into the waiting, the next to get the lock must be the producer), Consumer 2 judged that there was no resources to enter the waiting state; At this time producer 1 production, and notify Consumer 1, consumer 1 smooth consumption, and perform notify operation, but at this time consumer 2 but also because of resources and in the waiting state, thus awakened Consumers 2 (consumer 1 want to awaken other producers), At this time there is no resources, resulting in the entire program because the consumer 2 into the infinite waiting, formed a deadlock.

Through the above analysis, the root cause is: At the same time, several consumers or several producers in the waiting state, leading to consumers may awaken or consumers, or producers awakened or producers. So if we can guarantee that only one consumer is in a wait state (the same producer), it will ensure that the consumer wakes up to be a producer, so that the whole mission can go on smoothly. Here is the modified code:

The improved Consumer.java

Package Creatorandconsumer;

public class Consumer implements Runnable {
	/**
	 * Thread Resource * *
	private Plate Plate;

	/**
	 * Producer Lock: For locking at the same time only one producer can enter the critical section of production (if two producers enter the critical zone, then one of the producers may want to awaken the consumer but awaken the producer)/
	private static Object Consumerlocker = new Object ();

	Public Consumer (Plate Plate) {
		this.plate = Plate;
	}

	@Override public
	Void Run () {
		//must obtain a producer lock before producing
		synchronized (consumerlocker) {
			synchronized ( PLATE) {
				//If the number of eggs is greater than 0 at this point, then while
				(Plate.geteggnum () < 1) {
					try {//)
						This detail needs to be noted, if the thread enters wait, Then the lock on it will be temporarily released,
						//Otherwise the other thread can not be locked, and then wake up this thread
						plate.wait ();
					catch (Interruptedexception e) {
						E.printstacktrace ();
					}

				Wake up, the resource lock again, and the conditions can be assured to take the eggs
				Plate.getegg ();
				Plate.notify ();}}}


Improved Creator.java:

Package Creatorandconsumer;

/** *
 producer
 * * 
 @author Martin */Public
class Creator implements Runnable {
	/**
	 * Thread Resource
	 * *
	private Plate Plate;

	/**
	 * Producer Lock: For locking at the same time only one producer can enter the critical section of production (if two producers enter the critical zone, then one of the producers may want to awaken the consumer but awaken the producer)/
	private static Object Creatorlocker = new Object ();

	Public Creator (Plate Plate) {
		this.plate = Plate;
	}

	@Override public
	Void Run () {
		//must obtain a producer lock before producing
		synchronized (creatorlocker) {
			synchronized (plate {
				//If the number of eggs is greater than 0 at this point, then while
				(Plate.geteggnum () >= 5) {try {//)
						This detail needs to be noted, if the thread enters wait, Then the lock on it will be temporarily released,
						//Otherwise the other thread can not be locked, and then wake up this thread
						plate.wait ();
					catch (Interruptedexception e) {
						E.printstacktrace ();
					}

				After awakening, the resource lock is obtained again, and the condition can be satisfied with the eggs.
				Object egg = new Object ();
				Plate.addegg (egg);
				Plate.notify ();}}}


Improvement notes: The improved producer and consumer locks are added to the producer lock and Consumer lock, respectively, for locking at the same time only one consumer (producer) enters the production critical zone (if two producers enter the critical zone, then it is likely that one of the producers would have awakened the producer by awakening the consumer), In general, there are altogether three locks: consumer locks, producer locks, and locks shared by producers and consumers.

In the end, when writing multithreading, it should be noted that a resource may wake up all the threads that are waiting for that resource, so that the consumer thread may not wake up to the producer thread or the consumer thread.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.