Veamos un caso primero:
Demanda : una sala de cine muestra actualmente películas de gran éxito nacional, con un total de 100 entradas, y tiene 3 ventanas para vender entradas, por favor diseñe un programa para simular la venta de entradas de la sala de cine.
Ideas:
- Defina un ticket de clase para implementar la interfaz Runnable,
que define una variable miembro: private int tickets = 100; - Vuelva a escribir el método run () en la clase de entrada para implementar la venta de
entradas . Los pasos del código son los siguientes: A: Determine la cantidad de entradas para que sea mayor que 0, venda la entrada y diga en qué ventana
vender la entrada . B: Después de que se vende el boleto, el número total de boletos se reducirá en 1
C: si el boleto se ha ido, alguien puede venir a preguntar, por lo que aquí se usa un bucle infinito para mantener ejecutada la acción de venta de boletos - Defina una clase de prueba con un método principal. Los pasos del código son los siguientes
: A: Crea un objeto de la clase SellTicket
B: Crea tres objetos de la clase Thread, usa el objeto SelITicke como parámetro del método de construcción
y da el nombre de ventana correspondiente
C: iniciar el hilo
Veamos una implementación preliminar:
clase de ticket:
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--;
}
}
}
}
clase principal:
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();
}
}
Después de ejecutarlo, encontrará que hay dos problemas con este programa:
1. Aparece un número negativo de boletos
2. Un boleto se vende varias veces
Se cumplen tres condiciones cuando ocurre el problema:
- ¿Es un entorno de subprocesos múltiples?
- ¿Hay intercambio de datos?
- Si hay varias declaraciones para operar y compartir datos.
Obviamente, aquí solo se puede romper la tercera condición.
Solución : bloquee el código para que varias declaraciones operen y compartan datos, de modo que solo se pueda ejecutar un hilo en cualquier momento (es decir, el acceso mutuamente exclusivo en el sistema operativo )
- JAVA solo proporciona una forma de sincronizar bloques de código para resolver
- Formato de bloque de código de sincronización:
synchronized (任意对象) {
//相当于给代码加锁,任意对象就是一把锁
多条语句操作共享数据的代码
}
Veamos el código optimizado:
aquí está el método sleep () para simular el tiempo de emisión de boletos
Clase de entrada:
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--;
}
}
}
}
}
clase principal:
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();
}
}
Como resultado, se realizan tres ventanillas de venta de boletos, y los boletos no se repiten ni son negativos, lo más importante es bloquear el proceso de venta de boletos para lograr el acceso exclusivo mutuo.