JAVA------thread synchronization (detailed case explanation)

Let's look at a case first:

Demand : A movie theater is currently showing domestic blockbuster movies, with a total of 100 tickets, and it has 3 windows for selling tickets, please design a program to simulate the movie theater selling tickets


Ideas:

  1. Define a class ticket to implement the Runnable interface,
    which defines a member variable: private int tickets = 100;
  2. Rewrite the run() method in the ticket class to implement ticket
    sales . The code steps are as follows: A: Determine the number of tickets to be greater than 0, sell the ticket, and tell which window to
    sell the ticket . B: After the ticket is sold, the total number of tickets will be reduced by 1
    C: If the ticket is gone, someone may come to ask, so here an infinite loop is used to keep the ticket selling action executed
  3. Define a test class with a main method. The code steps are as follows
    : A: Create an object of the SellTicket class
    B: Create three objects of the Thread class, use the SelITicke object as the parameter of the construction method,
    and give the corresponding window name
    C: start the thread

Let's look at a preliminary implementation:
ticket class:

package 卖票;
//定义一个类SellTicket实现Runnable接口,
//里面定义一个成员变量: private int tickets= 100;

public class ticket implements Runnable{
    
    
	private int tickets=100;
	
	@Override
	public void run() {
    
    
		//A:判断票数大于0,就卖票,并告知是哪个窗口卖的
		//B:卖了票之后,总票数要减1
		//C:票没有了,也可能有人来问,所以这里用死循环让卖票的动作一直执行
		while(true) {
    
    
			if(tickets>0) {
    
    
				int temp=101-tickets;
				System.out.println(Thread.currentThread().getName()+"正在出售第"+temp+"张票");
				tickets--;
			}
		}
	}

}

main class:

package 卖票;

/*
 * 需求:某电影院目前正在上映国产大片,共有100张票,
 * 而它有3个窗口卖票,请设计一个程序模拟该电影院卖票

思路:
1.	定义一个类SellTicket实现Runnable接口,
 	里面定义一个成员变量: private int tickets= 100;
2.	在ellTicket类中重写run()方法实现卖票, 代码步骤如下
A:判断票数大于0,就卖票,并告知是哪个窗口卖的
B:卖了票之后,总票数要减1
C:票没有了,也可能有人来问,所以这里用死循环让卖票的动作一直执行

3.	定义一个测试类, 里面有main方法,代码步骤如下
A:创建SellTicket类的对象
B:创建三个Thread类的对象,把SelITicke对象作为构造方法的参数,
	并给出对应的窗口名称
C:启动线程
 */


public class ticketDemo {
    
    
	public static void main(String[] args) {
    
    
		ticket t=new ticket();
		
		Thread t1=new Thread(t,"窗口一");
		Thread t2=new Thread(t,"窗口二");
		Thread t3=new Thread(t,"窗口三");
		
		t1.start();
		t2.start();
		t3.start();
		
	}

}


After running, you will find that there are two problems with this program:
1. A negative number of tickets appears
2. A ticket is sold multiple times

Three conditions are met when the problem occurs:

  1. Is it a multi-threaded environment
  2. Is there data sharing
  3. Whether there are multiple statements to operate and share data

Obviously only the third condition can be broken here


Solution : Lock up the code for multiple statements to operate and share data, so that only one thread can execute at any time (that is, the mutually exclusive access in the operating system )

  • JAVA just provides a way to synchronize code blocks to solve
  • Synchronization code block format:
synchronized (任意对象) {
    
    //相当于给代码加锁,任意对象就是一把锁
多条语句操作共享数据的代码
}

Let's look at the optimized code:
here is the sleep() method to simulate the ticketing time


Ticket class:

package 卖票;
//定义一个类SellTicket实现Runnable接口,
//里面定义一个成员变量: private int tickets= 100;

public class ticket implements Runnable{
    
    
	private int tickets=100;
	private Object obj=new Object();
	
	@Override
	public void run() {
    
    
		//A:判断票数大于0,就卖票,并告知是哪个窗口卖的
		//B:卖了票之后,总票数要减1
		//C:票没有了,也可能有人来问,所以这里用死循环让卖票的动作一直执行
		while(true) {
    
    
			synchronized (obj) {
    
    
			if(tickets>0) {
    
    
				//通过sleep()方法模拟出票时间
				try {
    
    
					Thread.sleep(100);
				} catch (Exception e) {
    
    
					e.printStackTrace();
				}
				int temp=101-tickets;
				System.out.println(Thread.currentThread().getName()+"正在出售第"+temp+"张票");
				tickets--;
			}
		}
	  }
	}

}

main class:

package 卖票;

/*
 * 需求:某电影院目前正在上映国产大片,共有100张票,
 * 而它有3个窗口卖票,请设计一个程序模拟该电影院卖票

思路:
1.	定义一个类SellTicket实现Runnable接口,
 	里面定义一个成员变量: private int tickets= 100;
2.	在ellTicket类中重写run()方法实现卖票, 代码步骤如下
A:判断票数大于0,就卖票,并告知是哪个窗口卖的
B:卖了票之后,总票数要减1
C:票没有了,也可能有人来问,所以这里用死循环让卖票的动作一直执行

3.	定义一个测试类, 里面有main方法,代码步骤如下
A:创建SellTicket类的对象
B:创建三个Thread类的对象,把SelITicke对象作为构造方法的参数,
	并给出对应的窗口名称
C:启动线程
 */


public class ticketDemo {
    
    
	public static void main(String[] args) {
    
    
		ticket t=new ticket();
		
		Thread t1=new Thread(t,"窗口一");
		Thread t2=new Thread(t,"窗口二");
		Thread t3=new Thread(t,"窗口三");
		
		t1.start();
		t2.start();
		t3.start();
		
	}

}


As a result, three windows selling tickets are realized, and the tickets are not repeated and not negative. The most important thing is to lock the ticket selling process to achieve mutual exclusive access.

Guess you like

Origin blog.csdn.net/weixin_45102820/article/details/113762087