Java Multithreading--"upgraded" producer consumers

Source: Internet
Author: User

Reentrantlock Introduction

Reentrantlock is a reentrant mutex, also known as an "exclusive lock."

As the name implies, Reentrantlock locks can only be held by a single thread lock at the same point in time, whereas reentrant means that reentrantlock locks can be obtained multiple times by individual threads.
Reentrantlock is divided into " fair lock " and " non-fair lock ". The difference between them is fair in the mechanism of acquiring locks. "Locks" are designed to protect competing resources, prevent multiple threads from manipulating threads simultaneously, and reentrantlock can only be fetched by one thread at a time (when a thread acquires a "lock", other threads must wait). The Reentraantlock is a FIFO waiting queue to manage all threads that acquire the lock. Under the mechanism of "fair lock", threads queue to acquire the lock, while the "unfair lock" acquires the lock at the beginning of the queue, regardless of whether the lock is in the acquired state.


Reentrantlock Example

By comparing "Example 1" and "Example 2", we can clearly understand the role of lock and unlock.

Example 1

Import Java.util.concurrent.locks.lock;import java.util.concurrent.locks.reentrantlock;//LockTest1.java//Warehouse Class        Depot {private int size;        The actual number of warehouses private lock lock;        Exclusive lock Public Depot () {this.size = 0;    This.lock = new Reentrantlock ();        } public void produce (int val) {lock.lock ();            try {size + = Val;        System.out.printf ("%s produce (%d)--size=%d\n", Thread.CurrentThread (). GetName (), Val, size);        } finally {Lock.unlock ();        }} public void consume (int val) {lock.lock ();            try {size = val;        System.out.printf ("%s consume (%d) <--size=%d\n", Thread.CurrentThread (). GetName (), Val, size);        } finally {Lock.unlock (); }    }};        Producer class Producer {private Depot Depot;    Public Producer (Depot Depot) {this.depot = Depot;    }//Consumer products: Create a new thread to produce products in the warehouse. Public void Produce (final int val) {new Thread () {public void run () {depot.produce (val);    }}.start ();        }}//Consumer class Customer {private Depot Depot;    Public Customer (Depot Depot) {this.depot = Depot;    }//Consumer products: Create a new thread to consume the product from the warehouse. public void consume (final int. val) {new Thread () {public void run () {Depot.consume (val            );    }}.start ();        }}public class LockTest1 {public static void main (string[] args) {Depot mdepot = new Depot ();        Producer Mpro = new Producer (mdepot);        Customer MCus = new Customer (mdepot);        Mpro.produce (60);        Mpro.produce (120);        Mcus.consume (90);        Mcus.consume (150);    Mpro.produce (110); }}

Operation result :

Thread-0 Produce ()--size=60thread-1 produce (+)--size=180thread-3 consume (<--size=30thread-2) Consume (<--size=-60thread-4 produce)--size=50

result analysis :
(01) Depot is a warehouse. Through the produce () can produce goods in the warehouse, through the consume () can consume the goods in the warehouse. Exclusive lock lock allows for mutually exclusive access to the warehouse: The warehouse is locked through lock () before the goods are operated (in the production/consumption) warehouse, and then unlocked by unlock ().


(04) in the main thread main, we will create a new 1 producer Mpro and create 1 new consumer MCUs. They produce/consume products separately from the warehouse.
According to the number of production/consumption in Main, the final remaining product of the warehouse should be 50. The results of the operation are in line with our expectations!

There are two problems with this model:
(01) In reality, the capacity of the warehouse cannot be negative. However, the warehouse capacity in this model can be negative, which contradicts the reality!
(02) In reality, the capacity of the warehouse is limited. However, there is really no limit to the capacity in this model!
We'll talk a little bit about how to solve these two problems. Now, let's look at a simple example 2; by comparing "Example 1" and "Example 2", we can understand the use of lock (), unlock () more clearly.

Example 2

Import Java.util.concurrent.locks.lock;import java.util.concurrent.locks.reentrantlock;//LockTest2.java//Warehouse Class        Depot {private int size;        The actual number of warehouses private lock lock;        Exclusive lock Public Depot () {this.size = 0;    This.lock = new Reentrantlock ();            } public void produce (int val) {//Lock.lock ();//try {size + = Val;        System.out.printf ("%s produce (%d)-size=%d\n", Thread.CurrentThread (). GetName (), Val, size);// } catch (Interruptedexception e) {//} finally {//Lock.unlock ();/}} public void C            Onsume (int val) {//Lock.lock ();//try {size-= Val;        System.out.printf ("%s consume (%d) <--size=%d\n", Thread.CurrentThread (). GetName (), Val, size);// } finally {//Lock.unlock ();/}}};        Producer class Producer {private Depot Depot;    Public Producer (Depot Depot) {    This.depot = depot;    }//Consumer products: Create a new thread to produce products in the warehouse. public void produce (final int. val) {new Thread () {public void run () {Depot.produce (val            );    }}.start ();        }}//Consumer class Customer {private Depot Depot;    Public Customer (Depot Depot) {this.depot = Depot;    }//Consumer products: Create a new thread to consume the product from the warehouse. public void consume (final int. val) {new Thread () {public void run () {Depot.consume (val            );    }}.start ();        }}public class LockTest2 {public static void main (string[] args) {Depot mdepot = new Depot ();        Producer Mpro = new Producer (mdepot);        Customer MCus = new Customer (mdepot);        Mpro.produce (60);        Mpro.produce (120);        Mcus.consume (90);        Mcus.consume (150);    Mpro.produce (110); }}

Run result (running result is accidental):

Thread-0 Produce ()--size=-60thread-4 produce (+)--size=50thread-2 consume (all) <--size=-60thread-1 Produce (size=-60thread-3 consume) <--size=-60

Result Description :
Example 2 removes the lock lock on the basis of example 1. In Example 2, the final remaining product in the warehouse is-60, not the 50 we expect. The reason is that we did not implement mutually exclusive access to the warehouse.

Example 3

In Example 3, we solved two problems in example 1 by condition: "The capacity of the warehouse cannot be negative" and "the capacity of the warehouse is limited".
The problem is solved by condition. Condition is required to be used in conjunction with Lock: the await () method in condition allows the thread to block [similar to wait ()], and the wake-up thread [similar to notify ()] through the condition signal () method.

Import Java.util.concurrent.locks.lock;import Java.util.concurrent.locks.reentrantlock;import    java.util.concurrent.locks.condition;//locktest3.java//Warehouse class Depot {private int capacity;        The capacity of the warehouse private int size;        The actual number of warehouses private lock lock;            Exclusive lock private Condition fullcondtion;        Production conditions private Condition emptycondtion;        Consumption conditions public Depot (int capacity) {this.capacity = capacity;        this.size = 0;        This.lock = new Reentrantlock ();        This.fullcondtion = Lock.newcondition ();    This.emptycondtion = Lock.newcondition ();        } public void produce (int val) {lock.lock ();            try {//left means "quantity you want to produce" (it is possible to produce too much, which requires more production) int left = Val;                while (Left > 0) {//Inventory is full, wait for "consumer" consumer products.                while (size >= capacity) fullcondtion.await (); Get "Actual production quantity" (i.e. new quantity in inventory)//if "inventory" + "quantity to produce" > "Total Capacity", then "actual increaseVolume "=" Total Capacity "-" current capacity ". (Fills the warehouse at this time)//otherwise "actual increment" = "Quantity to be produced" int inc = (size+left) >capacity?                (capacity-size): left;                Size + = Inc;                Left-to-= Inc; System.out.printf ("%s produce (%3d)--left=%3d, Inc=%3d, size=%3d\n", Thread.CurrentThread (). g                Etname (), Val, left, Inc, size);                Inform "consumers" to consume.            Emptycondtion.signal ();        }} catch (Interruptedexception e) {} finally {Lock.unlock ();        }} public void consume (int val) {lock.lock ();            try {//left means "customer wants to consume quantity" (there may be too much consumption, not enough inventory, need to spend more) int left = Val;                while (Left > 0) {//stock is 0 o'clock, wait for "producer" to produce the product.                while (size <= 0) emptycondtion.await ();                 Get the "Quantity actually consumed" (that is, the quantity actually reduced in the inventory)//if "inventory" < "quantity that the customer wants to consume", then "actual consumption" = "inventory";//otherwise, "actual consumption" = "Quantity to be consumed by customer". IntDec = (size<left)?                Size:left;                Size-= Dec;                Left-= Dec; System.out.printf ("%s consume (%3d) <--left=%3d, dec=%3d, size=%3d\n", Thread.CurrentThread (). g                Etname (), Val, left, Dec, size);            Fullcondtion.signal ();        }} catch (Interruptedexception e) {} finally {Lock.unlock ();    }} public String toString () {return "Capacity:" +capacity+ ", Actual size:" +size; }};        Producer class Producer {private Depot Depot;    Public Producer (Depot Depot) {this.depot = Depot;    }//Consumer products: Create a new thread to produce products in the warehouse. public void produce (final int. val) {new Thread () {public void run () {Depot.produce (val            );    }}.start ();        }}//Consumer class Customer {private Depot Depot;    Public Customer (Depot Depot) {this.depot = Depot;    }//Consumer products: Create a new thread to consume the product from the warehouse. public void consume (final int val) {        New Thread () {public void run () {Depot.consume (val);    }}.start ();        }}public class LockTest3 {public static void main (string[] args) {Depot mdepot = new Depot (100);        Producer Mpro = new Producer (mdepot);        Customer MCus = new Customer (mdepot);        Mpro.produce (60);        Mpro.produce (120);        Mcus.consume (90);        Mcus.consume (150);    Mpro.produce (110); }}

Run results (one time) :

Thread-0 Produce ()--left=  0, inc=, size= 60thread-1 Produce (+)--left=, inc=, size=100thread- 2 Consume (<--) left=  0, dec=, size= 10thread-3 consume (<--left=140, dec=, size= 0thread-4  PR Oduce ()--left=, inc=100, size=100thread-3 consume (All) <--left=, dec=100, size=  0thread-4 Produce (1 --left=  0, inc=, size= 10thread-3 consume (<--left=), dec=, size= 0thread-1  Produce (120) --left=  0, inc=, size= 80thread-3 consume () <--left=  0, dec=, size= 50

The code already contains a very detailed comment, which is not explained here.
More on the producer/consumer model, you can refer to "Java multithreading-" simple " production consumer issues ".
The contents of condition are described in detail later.



Java Multithreading--"upgraded" producer consumers

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.