Java multithreaded programming (synchronization, deadlock, production consumption) :

This is the 30th day of my participation in the August Text Challenge.More challenges in August

Thread synchronization and deadlocks:

The concept of thread synchronization refers to the resource processing protection operation when several thread objects access resources in parallel.

Thread deadlock concept: refers to two threads are waiting for each other to complete first, resulting in the program stop state;

Understand the corresponding concepts first, then further understanding.

Synchronous:

An example: a semicolon, or a ticket issue

  1. There is no synchronization
  2. Open the three thread (conductor) test
package com.xbhog;
class MyThread implements Runnable {// Define the thread execution class
    private int ticket = 3;// The total number of votes is 6
    @Override
    public void run(a) {
        while (true) {	// Keep selling tickets
            if (this.ticket > 0) {	// There are tickets left
                try {
                    Thread.sleep(100);	// Simulate network latency
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // Get the current thread name
                System.out.println(Thread.currentThread().getName() +
                        "Ticket, ticket =" + this.ticket--);
            } else {
                System.out.println("***** is sold out *****");
                break;// Break the loop}}}}public class JavaMultithreaded core{
    public static void main(String[] args) throws Exception {
        MyThread mt = new MyThread();
        new Thread(mt, "Conductor A").start();	// Start the ticket selling thread
        new Thread(mt, "Conductor B").start();	// Start the ticket selling thread
        new Thread(mt, "Conductor C").start();	// Start the ticket selling thread}}Copy the code

Results:

First random run: Second random run:
Ticket seller B sells tickets, ticket = 2

Ticket seller C sells tickets, ticket = 3

Ticket seller A sells tickets, ticket = 3

Ticket seller A sells tickets, ticket = 1

Ticket seller B sells tickets, ticket = -1

The tickets have been sold out

Ticket seller C sells tickets, ticket = 0

The tickets have been sold out

The tickets have been sold out
Ticket seller B sells tickets, ticket = 1

The tickets have been sold out

Ticket seller A sells tickets, ticket = 3

The tickets have been sold out

Ticket seller C sells tickets, ticket = 2

The tickets have been sold out

The reason for this is because there are ambiguities in multithreaded access in two places in the code:

  1. this.ticket>0;
  2. this,ticket–;

Let’s say I have 1 left; When the first thread meets the ticket condition (without reducing the number of votes), other threads may also meet the ticket condition, so simultaneous decrement can result in a negative number!

To solve the above problems, thread synchronization technology is needed.

First of all, there are two ways to implement synchronized in Java:

  1. Synchronized code blocks (synchronized policies added inside methods)

    packageCom. Xbhog. Multithreading1;
    class MyThread implements Runnable {						// Define the thread execution class
        private int ticket = 3; 								// The total number of votes is 6
        @Override
        public void run(a) {
            while (true) {									// Keep selling tickets
                synchronized(this) {							// Synchronize code blocks
                    if (this.ticket > 0) {					// There are tickets left
                        try {
                            Thread.sleep(100);				// Simulate network latency
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() +
                                "Ticket, ticket =" + this.ticket--);
                    } else {
                        System.out.println("***** is sold out *****");
                        break;								// Break the loop
                    }
                }
            }
        }
    }
    public class JavaMultithreaded synchronized code block{
        public static void main(String[] args) {
            MyThread mt = new MyThread();
            new Thread(mt, "Conductor A").start();					// Start the ticket selling thread
            new Thread(mt, "Conductor B").start();					// Start the ticket selling thread
            new Thread(mt, "Conductor C").start();					// Start the ticket selling thread}}Copy the code
    Ticket A sells tickets, ticket is equal to 3 ticket C sells tickets, ticket is equal to 2 Ticket B sells tickets, ticket is equal to 1* * * ** The tickets are sold out* * * **
    * * * ** The tickets are sold out* * * **
    * * * ** The tickets are sold out* * * **
    Copy the code
  2. Synchronized methods (synchronized policies added to methods)

    class MyThread implements Runnable {						// Define the thread execution class
    	private int ticket = 3; 								// The total number of votes is 6
    	@Override
    	public void run(a) {
    		while (this.sale()) {								// Call the synchronous method; }}public synchronized boolean sale(a) {					// select * from ()
    		if (this.ticket > 0) {
    			try {
    				Thread.sleep(100); 						// Simulate network latency
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    			System.out.println(Thread.currentThread().getName() + 
    				"Ticket, ticket =" + this.ticket--);
    			return true;
    		} else {
    			System.out.println("***** is sold out *****");
    			return false; }}}public class ThreadDemo {
    	public static void main(String[] args) throws Exception {
    		MyThread mt = new MyThread();
    		new Thread(mt, "Conductor A").start();					// Start the ticket selling thread
    		new Thread(mt, "Conductor B").start();					// Start the ticket selling thread
    		new Thread(mt, "Conductor C").start();					// Start the ticket selling thread}}Copy the code
    Ticket A sells tickets, ticket is equal to 3 ticket C sells tickets, ticket is equal to 2 Ticket B sells tickets, ticket is equal to 1* * * ** The tickets are sold out* * * **
    * * * ** The tickets are sold out* * * **
    * * * ** The tickets are sold out* * * **
    Copy the code

The nature of synchronization: Only one thread is allowed to execute a resource at a time, so other thread objects will be in a waiting state while this thread object is executing.

Advantages and disadvantages of synchronization:

  1. The accuracy of data can be guaranteed

  2. Data thread access security


  3. The processing performance of the program deteriorates

Deadlock:

Example:

Now, if Tom wants Tom’s picture, and Tom wants Tom’s book, then Tom says to Tom: Give me your picture, and I’ll give you the book.

Li Si said to Zhang SAN, “Give me your book and I will draw for you.

At this point: Joe is waiting for Joe, Joe is waiting for Joe, and they have been waiting for him to form a deadlock;

Observe thread deadlock:

packageCom. Xbhog. Deadlock;class Book {
    public synchronized void tell(Painting paint) {		// Synchronize methods
        System.out.println("Zhang SAN said to Li Si: give me your picture and I'll give you a book. No picture, no book!");
        paint.get();
    }
    public synchronized void get(a) {						// Synchronize methods
        System.out.println(Zhang SAN got Li Si's painting and began to appreciate it seriously.); }}class Painting {
    public synchronized void tell(Book book) {				// Synchronize methods
        System.out.println("Li Si said to Zhang SAN: give me your book and I will draw for you. No book, no picture!");
        book.get();
    }
    public synchronized void get(a) {						// Synchronize methods
        System.out.println("Li Si got Zhang SAN's book and began to read it carefully."); }}public class DeadLock implements Runnable{
    private Book book = new Book();
    private Painting paint = new Painting();
    public DeadLock(a) {
        new Thread(this).start();
        book.tell(paint);
    }
    @Override
    public void run(a) {
        paint.tell(book);
    }
    public static void main(String[] args) {
        newDeadLock() ; }}Copy the code

Because deadlocks occur unpredictably, the code might not show up in a single run and need to be run several times to see the effect;

Effect:

The model of producer and consumer is derived from this.

Producer and Consumer issues:

First of all, it is necessary to make clear that producer and consumer are two thread objects, which are to save and read data from the same resource.

The basic operation is that the producer produces a resource and the consumer takes a resource, one by one.

Corresponding class diagram:

We need to think about the problem, what would happen if we didn’t do anything?

  1. Data misalignment: When the producer thread simply creates a stack space to store the information name and switches to the consumer thread when it wants to store the data but has not yet stored the data, the consumer thread will associate the information name with the content of the previous information, resulting in data misalignment.
  2. Duplicate data: when the producer has placed data several times before the consumer begins to fetch the data, or when the consumer has finished fetching the data but the producer has not yet produced new data.

To solve the above two problems, the following two knowledge points are involved:

  1. Set sync code block or set sync method >>> Resolve data error

  2. Object thread wait and wake up >>> Solve the problem of repeated data setting and repeated fetching

Add data synchronization method or synchronization code block:

In this program, producers and consumers represent thread objects, so synchronization operations can only be in the Message class. Set and GET methods can be set as separate synchronization methods.

class Message {
	private String title ;							// Save the title of the message
	private String content ;							// Save the contents of the message
	public synchronized void set(String title, String content) {
		this.title = title;
		try {
			Thread.sleep(200);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		this.content = content;
	}
	public synchronized String get(a) {
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		return this.title + "-- >" + this.content;
	}
	// Skip setter and getter
}
class Producer implements Runnable {					// Define the producer
	private Message msg = null ;
	public Producer(Message msg) {
		this.msg = msg ;
	}
	@Override
	public void run(a) {
		for (int x = 0; x < 50; x++) {				// Produce 50 times of data
			if (x % 2= =0) {
				this.msg.set("xbhog"."22");// Set the properties
			} else {
				this.msg.set("xbhog"."www.cnblog.cn/xbhog");// Set the properties}}}}class Consumer implements Runnable {					// Define the consumer
	private Message msg = null ;
	public Consumer (Message msg) {
		this.msg = msg ;
	}
	@Override
	public void run(a) {
		for (int x = 0; x < 50; x++) {				// Fetch data 50 times
			System.out.println(this.msg.get()); 		// Get attributes}}}public class ThreadDemo {
	public static void main(String[] args) throws Exception {
		Message msg = new Message() ;					// Define a Message object for storing and retrieving data
		new Thread(new Producer(msg)).start() ;		// Start the producer thread
		new Thread(new Consumer(msg)).start() ;		// Get the consumer thread}}Copy the code

Object thread wait and wake up mechanism:

Thread wait and wake up can only rely on Object to complete, if you want to let producers and consumers take one, one by one, then need to add flag bits to determine the current state of the thread;

As shown in the figure:

When the producer thread and consumer thread enter, check whether the current flag bit is true.

  1. True: producers can produce resources, but consumers cannot take them away

  2. False: Indicates that the producer cannot produce resources, but the consumer needs to take resources

class Message {
	private String title ;
	private String content ;
	private boolean flag = true; 					// indicates the form of production or consumption
	// flag = true: production is allowed, but consumption is not allowed
	// flag = false: consumption is allowed, production is not allowed
	public synchronized void set(String title,String content) {
		if (this.flag == false) {						// Unable to produce, waiting to be consumed
			try {
				super.wait();
			} catch(InterruptedException e) { e.printStackTrace(); }}this.title = title ;
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		this.content = content ;
		this.flag = false ; 							// It has already been produced
		super.notify(); 								// Wake up the waiting thread
	}
	public synchronized String get(a) {
		if (this.flag == true) {						// Not yet produced, need to wait
			try {
				super.wait();
			} catch(InterruptedException e) { e.printStackTrace(); }}try {
			Thread.sleep(10);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		try {
			return this.title + "-" + this.content ;
		} finally {										// Do it anyway
			this.flag = true ; 							// Continue production
			super.notify(); 								// Wake up the waiting thread}}}Copy the code

In this program to add a data generation and consumption of the control logic member attributes, through the value of the program to control the implementation of thread waiting and wake up processing operations, so as to solve the problem of repeated operations thread.

The end:

If you see this or happen to help you, please click 👍 or ⭐ thank you;

There are mistakes, welcome to point out in the comments, the author will see the modification.