Java multithreading ----- negative number in ticket sales

      1, Problem description    

         As a multi-threaded entry problem, ticket selling must be familiar to everyone. For a new multi-threaded Xiaobai, there will inevitably be various problems when writing code. And I found that the ticket sales results were 0 and negative,   Don't say much, as evidenced by the screenshot:

          The above five threads are newly created, but four results are wrong. If I write this way, no matter how many new threads are created, there will eventually be n-1 result errors. If you have the same problem as me, please keep looking.

        2, Error code

        First of all, what is my wrong way of writing?

        Upper Code:

package com.example.demo.threadTest;

/**
 * @ClassName: Test7
 * @Author: wnn
 * @Description: Three ticket windows sell 20 tickets at the same time
 * @Date: 2021/10/14 14:11
 */
public class Test7 {
    public static void main(String[] args) {
        SellTickets sellTickets = new SellTickets();
        //Create three threads
        for (int i = 1; i <= 3; i++) {
            Thread thread = new Thread(sellTickets, "thread " + i);
            thread.start();
        }
    }
}

//Ticket sales
class SellTickets1 implements Runnable {
    static int tickets = 20;
    static Object object = new Object();

    @Override
    public void run() {
        while (tickets > 0) {
            synchronized (object) {
                System.out.println(System.currentTimeMillis() + "-----" + Thread.currentThread().getName() + "Selling the third" + tickets + "Ticket");
                tickets--;
                try {
                    Thread.sleep(1000);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
    }
}

          The output results are as follows:

        It can be seen that there are two recording errors. So what is the reason for my mistake? In the ticket sales category, I also made a digital judgment. tickets need to be greater than 0, so after the last ticket is sold, the while loop should not be executed. Then the result was not what I expected.

        3, Reason answer

        After my hard thinking and repeated demonstration, I finally have my own understanding of multithreading.

        The three threads created will execute the code together, that is, the while judgment in the run() method. When it is found that it is greater than 0, it will enter the loop body. However, due to the lock of the synchronized synchronization code block, it means that only one thread can sell tickets at the same time.

        But here's the point. Although the thread entering the loop body may not occupy the CPU and enter the synchronous code block, it has entered the loop body. As long as it occupies the lock, it can execute the operation of ticket -.

        Therefore, after a thread sells the last ticket and releases the lock resources, the threads that have entered the loop body before will compete for the cpu again and continue to sell tickets until all threads entering the loop body have entered the synchronous code block and sold tickets.

        If you still don't understand the above expression, you can look at the adapted code (only the ticket selling class is released):

//Ticket sales
class SellTickets implements Runnable {
    static int tickets = 20;
    static Object object = new Object();
    @Override
    public void run() {
        while (tickets > 0) {
            System.out.println(System.currentTimeMillis() + "-----" +Thread.currentThread().getName()); //Used to determine the threads entering at the same time
            synchronized (object) {
                if (tickets ==0) {
                    System.exit(0);//Exit program
                }
                System.out.println(System.currentTimeMillis() + "-----" + Thread.currentThread().getName() + "Selling the third" + tickets + "Ticket");
                tickets--;
                try {
                    Thread.sleep(1000);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
    }
}

          The execution results of the above code can be tried by yourself.

          Let me explain the results below. As can be seen from the results in the figure below, two threads did enter the loop body at time 28, but since thread 1 obtained the lock, it entered the synchronization code block to sell tickets. However, thread 2 will continue to compete for cpu in the loop body.

 

 

          Then, after adding the if judgment, even if the thread enters the synchronization code block, the exit operation will be enforced because the ticket has been sold out, and the result will not continue to decrease.

        4, Write at the end

        I don't know if you understand my expression. Welcome to communicate.  

Keywords: Java Multithreading

Added by marowa on Thu, 14 Oct 2021 10:39:59 +0300