最初にケースを見てみましょう:
需要:映画館は現在、国内の大ヒット映画を上映しており、合計100枚のチケットがあり、チケットを販売するための3つのウィンドウがあります。チケットを販売する映画館をシミュレートするプログラムを設計してください
アイデア:
メンバー変数を定義するRunnableインターフェースを実装するためのクラスチケットを定義します。privateinttickets = 100;- チケット
販売を実装するために、チケットクラスのrun()メソッドを書き直します。コードステップは次のとおりです。A:チケットの数を0より大きいかどうかを決定し、チケットを
販売し、チケットを販売するウィンドウを指定します。B:チケットが販売された後、チケットの総数は1
C減少します。チケットがなくなった場合、誰かが尋ねてくる可能性があるため、ここでは無限ループを使用してチケット販売アクションを実行し続けます。 - mainメソッドを使用してテストクラスを定義します。コードの手順は次のとおり
です。A:SellTicketクラスのオブジェクトを作成します
。B:Threadクラスのオブジェクトを3つ作成し、SelITickeオブジェクトを構築メソッドのパラメーターとして使用し
て、対応するウィンドウ名
C:スレッドを開始します
予備的な実装を見てみましょう:
チケットクラス:
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--;
}
}
}
}
メインクラス:
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();
}
}
実行後、このプログラムには2つの問題があることがわかり
ます。1。負の数のチケットが表示される
2.チケットが複数回販売される
問題が発生すると、次の3つの条件が満たされます。
- マルチスレッド環境ですか
- データ共有はありますか
- データを操作および共有するためのステートメントが複数あるかどうか
明らかに、ここで破ることができるのは3番目の条件だけです。
解決策:複数のステートメントのコードをロックしてデータを操作および共有し、一度に1つのスレッドのみを実行できるようにします(つまり、オペレーティングシステムでの相互に排他的なアクセス)。
- JAVAは、コードブロックを同期して解決する方法を提供するだけです
- 同期コードブロック形式:
synchronized (任意对象) {
//相当于给代码加锁,任意对象就是一把锁
多条语句操作共享数据的代码
}
最適化されたコードを見てみましょう。これ
は、発券時間をシミュレートするためのsleep()メソッドです。
チケットクラス:
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--;
}
}
}
}
}
メインクラス:
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();
}
}
その結果、チケットを販売する3つのウィンドウが実現され、チケットが繰り返されたり、ネガティブになったりすることはありません。最も重要なことは、チケット販売プロセスをロックして、相互に排他的なアクセスを実現することです。