Thread Basic State Diagram:
The graph shows the basic state of the thread running: after the thread calls the start() method, it enters the runnable state, switching between runnable and runnable with CPU resource scheduling, and entering the blocking state when it encounters blockage.
1. New, create a new thread
2. Runnable, after calling the start method, the thread is ready to wait for CPU usage.
3. Running. The thread runs formally and executes the code in run.
4. Blocked. Blocked state can be divided into several situations: calling wait method; thread acquiring synchronous lock of object; calling sleep or join method; issuing IO request.
5. Dead, when the thread has finished executing, or exits the run method for other reasons, it ends its life cycle.
Synchronized Thread State Diagram
When a resource is accessed by a thread, it is locked, and other threads enter a Lock pool.
When the lock is released, other threads acquire the lock and become runnable.
Thread state diagrams that incorporate interaction between threads
After calling the wait() method, the thread releases the lock and enters the Wait pool; after receiving the notification, it waits for the lock to be acquired before it can run.
Thread blocking may be due to the following five reasons:
(<Thinking in Java>)
1. Call sleep (milliseconds) to put the thread into sleep. This thread will not run for a specified time.
2. Susnd () is used to suspend thread execution. Unless a resume() message is received, it will not return to a "runnable" state.
3. The thread execution is suspended with wait(). Threads do not become "runnable" unless they receive notify() or notifyAll() messages.
4. Threads are waiting for some IO operations to complete.
5. Threads try to call the "synchronization" method of another object, but that object is locked and temporarily unavailable.
Reference resources:
Java Multithread (8) Thread State Diagram
Producer/consumer issues
The wait() / nofity() method is the two methods of the base class Object, which means that all Java classes will have these two methods, so that we can implement synchronization mechanism for any object.
wait() method: when the buffer is full / empty, the producer / consumer thread stops its execution, abandons the lock, makes itself in a wait state, and lets other threads execute.
notify() method: when the producer / consumer puts / withdraws a product to the buffer, it sends an executable notification to other waiting threads, and abandons the lock to keep itself in a waiting state.
1 wait method:
This method belongs to Object's method. The purpose of the wait method is to stop the execution of the thread calling the part of the wait method (code block), release the lock of the code block where the call wait is currently obtained, and restore to the competitive lock state when other threads call the notify or notifyAll method (once the lock is acquired, the execution is resumed).
There are several points to note when calling the wait method:
First point: when a wait is called, it must be in a block of code that has a lock (synchronized modifier).
Second point: After resuming execution, the execution starts from the next statement of wait, so the wait method should always be called in the while loop to avoid the situation that the condition of resuming execution after resuming execution is not satisfied but continues execution.
Third point: If there is time in the wait method parameter, then in addition to notify and notify All being invoked to activate the thread in wait state (waiting state) to enter lock contention, the thread will also be activated to contention state in other threads after interrupt or parameter time has arrived.
Fourth point: The thread whose wait method is called must retrieve the lock that was released when it was executed to wait before it can resume execution.
2 notify method and notify All method:
The notify method notifies the call to the wait method, but a thread that has not yet been activated enters the thread scheduling queue (i.e., entering lock contention), noting that it is not executed immediately. And which thread is not guaranteed. Another point is that the awakened thread must be waiting for the lock released by wait.
3 synchronized keywords:
First point: When synchronized is used to identify a common method, it means that to execute the method, a thread must acquire the lock of the object in which the method is located.
Second point: When synchronized is used to identify a static method, it means that to execute the method, a thread must obtain the class lock of the class in which the method is located.
Third point: synchronized modifies a block of code. Similar to this: synchronized (obj) {//code... }. Represents that a thread must acquire an obj lock to execute the block of code. The purpose of this is to reduce the granularity of locks and ensure that the whole object is not locked when the locks required by different blocks do not conflict. Using zero-length byte array objects to do obj is very economical.
Be careful:
The remove method in LinkedList:
1. remove(): The first item is removed
2. remove(int index): Remove the specified item
3. remove(Object o): Remove objects that exist
In addition, every element remove d from the List moves forward. (position changes).
Reference resources: Problems to be noted when using remote method in List
Warehouse class
import java.util.LinkedList;
/**
* Created by Administrator on 2017/6/17.
*/
public class Storage {
// Maximum Storage in Warehouse
private final int MAX_SIZE = 100;
// Carrier of warehouse storage
private LinkedList<Object> list = new LinkedList<Object>();
// Production of num products
public void produce(int num) {
// Synchronization code segment
synchronized (list) {
//When the shared space is full, the producer cannot continue the production cycle to determine whether it is full. If it is full, wait the thread and release the lock to allow other synchronization methods to execute.
// If warehouse surplus capacity is insufficient
while (list.size() + num > MAX_SIZE) {//The warehouse is full and can't be reproduced.
System.out.println("+++++++++++[Quantity of products to be produced]:" + num + "/t[Inventory:"
+ list.size() + "/t Temporarily unable to carry out production tasks!");
try {
// Production is blocked due to unsatisfactory conditions
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// To produce num products when production conditions are satisfied
for (int i = 1; i <= num; ++i) {
list.add(new Object());
}
System.out.println("++[Number of products already produced]:" + num + "/t[Current storage capacity]:" + list.size());
list.notifyAll();
}
}
// Consumption of num products
public void consume(int num) {
// Synchronization code segment
synchronized (list) {
//The shared space space space space-time consumer can not continue to consume the consumption cycle to determine whether it is empty. If empty, wait the thread and release the lock to allow other synchronization methods to execute.
// If warehouse storage is insufficient
while (list.size() < num) {//The warehouse is empty and can no longer be consumed.
System.out.println("-------------[Quantity of products to be consumed]:" + num + "/t[Inventory:"
+ list.size() + "/t Can't execute the consumption task for the time being!");
try {
// Consumption congestion due to unsatisfactory conditions
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// Consumption of num products under satisfying consumption conditions
for (int i = 1; i <= num; ++i) {
list.remove();//Remove the first
}
System.out.println("--[Number of products already consumed]:" + num + "/t[Current storage capacity]:" + list.size());
list.notifyAll();
}
}
// get/set method
public LinkedList<Object> getList() {
return list;
}
public void setList(LinkedList<Object> list) {
this.list = list;
}
public int getMAX_SIZE() {
return MAX_SIZE;
}
}
Producer:
/**
* Created by Administrator on 2017/6/17.
*/
public class MyProducer extends Thread
{
// Quantity of products produced at a time
private int num;
// The warehouse where it is placed
private Storage storage;
// Constructor to set up the warehouse
public MyProducer(Storage storage)
{
this.storage = storage;
}
// Thread run function
public void run()
{
produce(num);
}
// Call the warehouse Storage production function
public void produce(int num)
{
storage.produce(num);
}
// get/set method
public int getNum()
{
return num;
}
public void setNum(int num)
{
this.num = num;
}
public Storage getStorage()
{
return storage;
}
public void setStorage(Storage storage)
{
this.storage = storage;
}
}
Consumer:
/**
* Created by Administrator on 2017/6/17.
*/
public class MyConsumer extends Thread
{
// Quantity of products consumed at a time
private int num;
// The warehouse where it is placed
private Storage storage;
// Constructor to set up the warehouse
public MyConsumer(Storage storage)
{
this.storage = storage;
}
// Thread run function
public void run()
{
consume(num);
}
// Call the warehouse Storage production function
public void consume(int num)
{
storage.consume(num);
}
// get/set method
public int getNum()
{
return num;
}
public void setNum(int num)
{
this.num = num;
}
public Storage getStorage()
{
return storage;
}
public void setStorage(Storage storage)
{
this.storage = storage;
}
}
Test class:
/**
* Created by Administrator on 2017/6/17.
*/
public class Test {
public static void main(String[] args) {
// Warehouse objects
Storage storage = new Storage();
// Producer Object
MyProducer p1 = new MyProducer(storage);
MyProducer p2 = new MyProducer(storage);
MyProducer p3 = new MyProducer(storage);
MyProducer p4 = new MyProducer(storage);
MyProducer p5 = new MyProducer(storage);
MyProducer p6 = new MyProducer(storage);
MyProducer p7 = new MyProducer(storage);
// Consumer Target
MyConsumer c1 = new MyConsumer(storage);
MyConsumer c2 = new MyConsumer(storage);
MyConsumer c3 = new MyConsumer(storage);
// Setting the Production Quantity of Producer's Products
p1.setNum(10);
p2.setNum(10);
p3.setNum(10);
p4.setNum(10);
p5.setNum(10);
p6.setNum(10);
p7.setNum(80);
// Setting Consumer Product Consumption Quantity
c1.setNum(50);
c2.setNum(20);
c3.setNum(30);
// Threads start execution
c1.start();
c2.start();
c3.start();
p1.start();
p2.start();
p3.start();
p4.start();
p5.start();
p6.start();
p7.start();
}
}
Operation results:
---------[The quantity of products to be consumed]: 50/t [Inventory]: 0/t can not execute the task of consumption for the time being! ++ [Number of Products Produced] 10/t [Current Storage] 10 ++ [Number of Products Produced] 10/t [Current Storage] 20 ---------[The number of products to be consumed]: 50/t [Inventory]: 20/t can not execute the task of consumption for the time being! ++ [Number of Products Produced] 10/t [Current Storage] 30 ++ [Number of Products Produced] 10/t [Current Storage] 40 ---------[The number of products to be consumed] 50/t [Inventory] 40/t can not perform the task of consumption for the time being! ++ [Number of Products Produced] 10/t [Current Storage] 50 --[Number of consumed products] 30/t [Current warehouse capacity] 20 ---------[The number of products to be consumed]: 50/t [Inventory]: 20/t can not execute the task of consumption for the time being! --[Number of consumed products already]: 20/t [Current warehouse capacity]: 0 ---------[The quantity of products to be consumed]: 50/t [Inventory]: 0/t can not execute the task of consumption for the time being! ++ [Number of Products Produced] 10/t [Current Storage] 10 ---------[The number of products to be consumed] 50/t [Inventory] 10/t can not perform the task of consumption for the time being! ++ [Number of Products Produced] 80/t [Current Storage] 90 --[Number of consumed products already]: 50/t [Current storage capacity]: 40