[Yugong series] Java Teaching Course 60 thread synchronization in January 2022

Posted by tiagofrancis on Wed, 19 Jan 2022 07:28:24 +0100

Article catalog

1, Thread synchronization

1. Ticket sales

  • Case requirements

A cinema is currently showing domestic blockbusters, with a total of 100 tickets, and it has three windows for ticket sales. Please design a program to simulate the ticket sales of the cinema

  • Implementation steps

Define a class SellTicket to implement the Runnable interface, which defines a member variable: private int tickets = 100;

Rewrite the run() method in SellTicket class to realize ticket selling. The code steps are as follows

If the number of votes is greater than 0, sell the tickets and tell which window it is sold

After selling the tickets, the total number of votes will be reduced by 1

The ticket is sold out and the thread stops

The selltimo class has the following test steps

Create an object of SellTicket class

Create three Thread class objects, take the SellTicket object as the parameter of the construction method, and give the corresponding window name

Start thread

  • code implementation
public class SellTicket implements Runnable {
    private int tickets = 100;
    //Rewrite the run() method in SellTicket class to realize ticket selling. The code steps are as follows
    @Override
    public void run() {
        while (true) {
            if(ticket <= 0){
                    //out of stock
                    break;
                }else{
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    ticket--;
                    System.out.println(Thread.currentThread().getName() + "Selling tickets,Remaining" + ticket + "Ticket");
                }
        }
    }
}
public class SellTicketDemo {
    public static void main(String[] args) {
        //Create an object of SellTicket class
        SellTicket st = new SellTicket();

        //Create three Thread class objects, take the SellTicket object as the parameter of the construction method, and give the corresponding window name
        Thread t1 = new Thread(st,"Window 1");
        Thread t2 = new Thread(st,"Window 2");
        Thread t3 = new Thread(st,"Window 3");

        //Start thread
        t1.start();
        t2.start();
        t3.start();
    }
}

2. Problems of ticket selling cases

  • There is a problem selling tickets
    • The same ticket appeared many times
    • There were negative votes
  • Causes of problems Due to the randomness of thread execution, the execution right of cpu may be lost during ticket selling, resulting in problems

3. Synchronize code blocks to solve data security problems

  • Conditions for safety problems

Is a multithreaded environment

Shared data

Multiple statements operate on shared data

  • How to solve the problem of multithreading security?

Basic idea: let the program have no security environment

  • How?

Lock the code for multiple statements to operate the shared data, so that only one thread can execute at any time

Java provides a way to synchronize code blocks

  • Sync code block format:
synchronized(Any object) { 
	Code for multiple statements to operate on shared data 
}
  • Synchronized (arbitrary object): it is equivalent to locking the code, and any object can be regarded as a lock
  • Advantages and disadvantages of synchronization
    • Benefits: it solves the data security problem of multithreading
    • Disadvantages: when there are many threads, each thread will judge the lock on synchronization, which is very resource-consuming and will virtually reduce the running efficiency of the program
  • Code demonstration
public class SellTicket implements Runnable {
    private int tickets = 100;
    private Object obj = new Object();

    @Override
    public void run() {
        while (true) {
            synchronized (obj) { // Lock the code that may have security problems. Multiple threads must use the same lock
                //When t1 comes in, it will lock this code
                if (tickets > 0) {
                    try {
                        Thread.sleep(100);
                        //t1 rest 100ms
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //Window 1 is selling ticket 100
                    System.out.println(Thread.currentThread().getName() + "The second is being sold" + tickets + "Ticket");
                    tickets--; //tickets = 99;
                }
            }
            //When t1 comes out, the lock of this code is released
        }
    }
}

public class SellTicketDemo {
    public static void main(String[] args) {
        SellTicket st = new SellTicket();

        Thread t1 = new Thread(st, "Window 1");
        Thread t2 = new Thread(st, "Window 2");
        Thread t3 = new Thread(st, "Window 3");

        t1.start();
        t2.start();
        t3.start();
    }
}

4. The synchronization method solves the problem of data security

  • Format of synchronization method

Synchronization method: add the synchronized keyword to the method

Modifier  synchronized Return value type method name(Method parameters) { 
	Method body;
}
  • What is the lock object of the synchronization method? ​ this
  • Static synchronization method Synchronous static method: add the synchronized keyword to the static method
Modifier  static synchronized Return value type method name(Method parameters) { 
	Method body;
}
  • What is the lock object for synchronous static methods? Class name class
  • Code demonstration
public class MyRunnable implements Runnable {
    private static int ticketCount = 100;

    @Override
    public void run() {
        while(true){
            if("Window one".equals(Thread.currentThread().getName())){
                //Synchronization method
                boolean result = synchronizedMthod();
                if(result){
                    break;
                }
            }

            if("Window II".equals(Thread.currentThread().getName())){
                //Synchronous code block
                synchronized (MyRunnable.class){
                    if(ticketCount == 0){
                       break;
                    }else{
                        try {
                            Thread.sleep(10);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        ticketCount--;
                        System.out.println(Thread.currentThread().getName() + "Selling tickets,Remaining" + ticketCount + "Ticket");
                    }
                }
            }

        }
    }

    private static synchronized boolean synchronizedMthod() {
        if(ticketCount == 0){
            return true;
        }else{
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ticketCount--;
            System.out.println(Thread.currentThread().getName() + "Selling tickets,Remaining" + ticketCount + "Ticket");
            return false;
        }
    }
}


public class Demo {
    public static void main(String[] args) {
        MyRunnable mr = new MyRunnable();

        Thread t1 = new Thread(mr);
        Thread t2 = new Thread(mr);
  
        t1.setName("Window one");
        t2.setName("Window II");
  
        t1.start();
        t2.start();
    }

}

5.Lock lock

Although we can understand the Lock object problem of synchronization code blocks and synchronization methods, we do not directly see where the Lock is added and where the Lock is released. In order to more clearly express how to add and release the Lock, JDK5 provides a new Lock object Lock

Lock is an interface that cannot be instantiated directly. Its implementation class ReentrantLock is used to instantiate it here

  • ReentrantLock construction method
  • Locking and unlocking method
  • Code demonstration
public class Ticket implements Runnable {
    //Number of tickets
    private int ticket = 100;
    private Object obj = new Object();
    private ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            //synchronized (obj) {/ / multiple threads must use the same lock
            try {
                lock.lock();
                if (ticket <= 0) {
                    //out of stock
                    break;
                } else {
                    Thread.sleep(100);
                    ticket--;
                    System.out.println(Thread.currentThread().getName() + "Selling tickets,Remaining" + ticket + "Ticket");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
            // }
        }
    }
}

public class Demo {
    public static void main(String[] args) {
        Ticket ticket = new Ticket();

        Thread t1 = new Thread(ticket);
        Thread t2 = new Thread(ticket);
        Thread t3 = new Thread(ticket);

        t1.setName("Window one");
        t2.setName("Window II");
        t3.setName("Window three");

        t1.start();
        t2.start();
        t3.start();
    }
}

6. Deadlock

  • summary Thread deadlock refers to that two or more threads hold the resources required by each other, resulting in these threads being in a waiting state and unable to execute
  • Under what circumstances will deadlock occur
    1. Limited resources
    2. Synchronous nesting
  • Code demonstration
public class Demo {
    public static void main(String[] args) {
        Object objA = new Object();
        Object objB = new Object();

        new Thread(()->{
            while(true){
                synchronized (objA){
                    //Thread one
                    synchronized (objB){
                        System.out.println("Well off students are walking");
                    }
                }
            }
        }).start();

        new Thread(()->{
            while(true){
                synchronized (objB){
                    //Thread two
                    synchronized (objA){
                        System.out.println("Xiao Wei is walking");
                    }
                }
            }
        }).start();
    }
}