JAVA ------スレッド同期(詳細なケースの説明)

最初にケースを見てみましょう:

需要:映画館は現在、国内の大ヒット映画を上映しており、合計100枚のチケットがあり、チケットを販売するための3つのウィンドウがあります。チケットを販売する映画館をシミュレートするプログラムを設計してください


アイデア:


  1. メンバー変数を定義するRunnableインターフェースを実装するためのクラスチケットを定義します。privateinttickets = 100;
  2. チケット
    販売を実装するために、チケットクラスのrun()メソッドを書き直します。コードステップは次のとおりです。A:チケットの数を0より大きいかどうかを決定し、チケットを
    販売し、チケット販売するウィンドウを指定ます。B:チケットが販売された後、チケットの総数は1
    C減少します。チケットがなくなった場合、誰かが尋ねてくる可能性があるため、ここでは無限ループを使用してチケット販売アクションを実行し続けます。
  3. 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つの条件が満たされます。

  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つのウィンドウが実現され、チケットが繰り返されたり、ネガティブになったりすることはありません。最も重要なことは、チケット販売プロセスをロックして、相互に排他的なアクセスを実現することです。

おすすめ

転載: blog.csdn.net/weixin_45102820/article/details/113762087