[advanced notes on Java basics] - Day06 - Chapter 2 thread safety

Advanced notes on Java Basics - Day06 - Chapter 2 thread safety

System: Win10
JDK: 1.8.0_121
IDE: IntelliJ IDEA 2017.3.7

2.1 thread safety

If there are multiple threads running at the same time, these threads may run this code at the same time. The result of each run of the program is the same as that of single thread, and the values of other variables are the same as expected, which is thread safe.
The following is a case to demonstrate thread safety:
Cinema ticket sales, we simulate the ticket sales process of the cinema. Assuming that the movie to be played is "love apartment", there are 100 seats in this movie (this movie can only sell 100 tickets)
Let's simulate the ticket window of the cinema to realize multiple windows selling tickets at the same time (multiple windows sell these 100 tickets together)
Use thread object to simulate window and Runnable interface subclass to simulate ticket selling
Simulated ticketing:

public class SellTicket implements Runnable {
    // Simulate 100 tickets
    private int tickets = 100;

    /**
     * Execute ticket selling operation
     */
    @Override
    public void run() {
        // Ticket selling operation of each window
        // The window is always open
        while (true) {
            // Use sleep to simulate the operation before selling tickets
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // When there are tickets
            if (tickets > 0) {
                // Ticket issuing operation
                // Gets the name of the current thread
                String name = Thread.currentThread().getName();
                System.out.println(name + "Is selling" + tickets + "Ticket");
                tickets--;
            }
        }
    }
}

Test class:

public class Test {
    public static void main(String[] args) {
        // Create thread task object
        SellTicket sell = new SellTicket();
        // Create three simultaneous ticket window objects
        Thread thread1 = new Thread(sell, "One window");
        Thread thread2 = new Thread(sell, "Window II");
        Thread thread3 = new Thread(sell, "Window three");

        // Sell tickets at the same time
        thread1.start();
        thread2.start();
        thread3.start();
    }
}

Operation results:

Two problems with the program were found:

  1. The same ticket will be sold many times, like the 100th ticket sold three times
  2. The number of votes was wrong. There were 100 tickets in total, but 102 tickets were sold

This phenomenon, the problem that the number of votes in several windows (threads) is not synchronized, is called thread insecurity

Thread safety problems are caused by global variables and static variables. If there are only read operations and no write operations for global variables and static variables in each thread, generally speaking, this global variable is thread safe; If multiple threads execute write operations at the same time, thread synchronization should generally be considered, otherwise thread safety may be affected

2.2 thread synchronization

When we use multiple threads to access the same resource, and there are write operations on the resource in multiple thread resources, thread safety problems are easy to occur
To solve the security problem of multi-threaded concurrent access to a resource mentioned above: that is, to solve the problem of duplicate tickets and multiple ticket sales, Java provides a synchronized mechanism to solve it
Briefly describe the solution according to the case:
When window 1 issues tickets, window 2 and window 3 can only do other irrelevant things and cannot issue tickets. After the operation of window 1 is completed, window 1, window 2 and window 3 have the opportunity to execute the ticket issuing operation. In other words, when a thread modifies a shared resource, other threads cannot modify the resource. After the modification is completed and synchronized, they can grab CPU resources and complete the corresponding operation, which ensures the synchronization of data and solves the problem of thread insecurity
In order to ensure that each thread can perform atomic operations normally, java introduces thread synchronization mechanism
So how to use it? There are three ways to complete synchronization:

  1. Synchronous code block
  2. Synchronization method
  3. Lock mechanism

2.3 synchronization code block

  • Synchronized code block: the synchronized keyword can be used in a block in a method, indicating that mutually exclusive access is only implemented to the resources of this block

Format:

synchronized(Synchronous lock){
    // Code requiring synchronous operation
}

Synchronous lock:
The synchronization lock of an object is just a concept, which can be understood as marking a lock on the object

  1. Lock object: can be any type
  2. Multiple thread objects, using the same lock

Note: at most one thread is allowed to have a synchronization lock at any time. Whoever gets the lock will enter the code block, and other threads cannot enter the code block

Use synchronous code blocks to solve:

public class SellTicket implements Runnable {
    // Simulate 100 tickets
    private int tickets = 100;

    Object obj = new Object();

    /**
     * Execute ticket selling operation
     */
    @Override
    public void run() {
        // Ticket selling operation of each window
        // The window is always open
        while (true) {
            // Use sleep to simulate the operation before selling tickets
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // Add the operation on the ticket to the synchronization code block
            synchronized (obj) {
                // When there are tickets
                if (tickets > 0) {
                    // Ticket issuing operation
                    // Gets the name of the current thread
                    String name = Thread.currentThread().getName();
                    System.out.println(name + "Is selling" + tickets + "Ticket");
                    tickets--;
                }
            }
        }
    }
}

Operation results:

When the synchronous code block is used, the above thread safety problem is solved

2.4 synchronization method

  • Synchronization method: the method modified by synchronized is called synchronization method, which ensures that when thread A executes this method, other threads can only wait outside the method

Format:

public synchronized void method() {
    // Code that may cause thread safety problems
}

Who is the synchronization lock?
For non static methods, the synchronization lock is this
For the static method, the bytecode object (class name. Class) of the class where the current method is located is used

The code of synchronization method is as follows:

public class SellTicket implements Runnable {
    // Simulate 100 tickets
    private int tickets = 100;

    Object obj = new Object();

    /**
     * Execute ticket selling operation
     */
    @Override
    public void run() {
        // Ticket selling operation of each window
        // The window is always open
        while (true) {
            // Use sleep to simulate the operation before selling tickets
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            sell();
        }
    }

    /**
     * Lock object: whoever calls this method is who
     * The implicit lock object is this
     */
    private synchronized void sell() {
        // When there are tickets
        if (tickets > 0) {
            // Ticket issuing operation
            // Gets the name of the current thread
            String name = Thread.currentThread().getName();
            System.out.println(name + "Is selling" + tickets + "Ticket");
            tickets--;
        }
    }
}

Operation results:

2.5 Lock lock

java.util.concurrent.locks.Lock mechanism provides a wider range of locking operations than synchronized code blocks and synchronized methods. Synchronized code blocks / synchronized methods have the functions of lock. In addition, it is more powerful and can better reflect object-oriented
Lock lock is also called synchronous lock. The method of adding lock and releasing lock is as follows:

  • public void lock(): add synchronization lock
  • Public void unload(): release the synchronization lock

Use the following:

public class SellTicket implements Runnable {
    // Simulate 100 tickets
    private int tickets = 100;

    // Initialize a lock object
    Lock myLock = new ReentrantLock();
    /**
     * Execute ticket selling operation
     */
    @Override
    public void run() {
        // Ticket selling operation of each window
        // The window is always open
        while (true) {
            // Use sleep to simulate the operation before selling tickets
            try {
                Thread.sleep(5);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            myLock.lock(); // Add synchronous lock
            // When there are tickets
            if (tickets > 0) {
                // Ticket issuing operation
                // Gets the name of the current thread
                String name = Thread.currentThread().getName();
                System.out.println(name + "Is selling" + tickets + "Ticket");
                tickets--;
            }
            myLock.unlock(); // Release synchronization lock
        }
    }
}

Operation results:

Tags: Java thread lock synchronized

Posted by MadnessRed on Sat, 26 Mar 2022 06:01:57 +0300