マルチスレッド-並行プログラミング(5)-スレッドセーフとインスタンスノートとの同期

スレッドセーフの問題
複数のスレッドが同じリソースを共有(アクセス)する可能性があります
//たとえば、同じオブジェクト、同じ変数、同じファイル
にアクセスする複数のスレッドが同じリソースにアクセスすると、データの混乱やデータのセキュリティの問題が発生しやすくなります。スレッドセーフの問題


複数のスレッドが同じリソース
を共有し、少なくとも1つのスレッドが書き込み操作を実行している場合、どのような状況でスレッドセーフの問題が発生しますか

例:お金の預け入れと引き出しの
問題
には、お金の預け入れと引き出しの2つのスレッドがあります。

   存钱                      取钱
   线程1         余额         线程2
   1000  《----1000------》 1000
   1000+1000-----》2000
                500 《-----1000-500


//正解:残高は500ではなく終了後1500である必要があります

チケット
を販売するための2つのスレッドがあります

   卖票                      卖票
   线程1         票数         线程2
   1000  《----1000------》 1000
   1000-1-----》999
                999 《-----1000-1

//正解:残高は、999ではなく終了後998である必要があります

購入チケットの問題エラーの例(スレッドの同期ではない):

public class love implements Runnable{
    private int piao=3000;//有3000张票
    public boolean sale() {//ture代表还有票;false代表没有票了
        if(piao<1) return false;
         piao--;//卖1张票
         
         //细化piao--;
         //寄存器=piao;
         //寄存器=寄存器-1;
         //piao=寄存器;
         
         String sk =Thread.currentThread().getName();//获取当前线程(买票窗口)的名字
         System.out.println(sk+"卖了1张票,还剩下"+piao+"张");
         return piao>1;
    }
    public void run() {
         while(sale());//循环执行;直至卖完票返回false
    }
}

public class Main {
    public static void main(String[] a) {
        love tjlove =new love();
        for(int i=1;i<=4;i++) {//循环4次;产生4个线程(窗口)卖票
            Thread tj = new Thread(tjlove());
            tj.setName(""+i);
            tj.start();
        }
    }
}

部分出力:

スレッドセーフの問題-問題の分析

线程A和B对类中1个变量值为17进行+1操作
最终结果为2个18

スレッドセーフの問題-解決策
ロック:

过程:首先线程A先访问到这个17,读上来后进行加锁并进去+1的操作改为18
并且17在加锁期间其它线程都不能访问
改完之后再进行写入,然后再解锁17
然后再由线程B去访问它,再进行加锁,重复上面操作变成19再解锁
这样做能保证在同一时间只有1个线程去访问它,这样就保证了安全;之前错误是由于这些线程一起去访问了它

スレッド同期
上記のロック操作はスレッド同期テクノロジーです。スレッド同期テクノロジー
を使用して、スレッドの安全性の問題を解決できます
。Javaでのスレッド同期には2つの方法があります
。1。同期ステートメント
2.同期方法

スレッドの同期-同期ステートメント

public class love implements Runnable{
	private int piao=3000;//本人cpu单核性能过强,数据量大些才能看到是4个线程在卖票
	public boolean sale() {
		synchronized(this) {//1个线程获取这个对象的锁,并加锁;    synchronized作用于整个语句
		//this指向当前对象
		//不能用new Object();这样会产生新的对象,产生新的锁
		//把this换成"123",效果基本一样;因为其存在常量值里,每次访问的对象一样
			if(piao<1) return false;
			piao--;
			String sk =Thread.currentThread().getName();
			System.out.println(sk+"卖了1张票,还剩下"+piao+"张");
			return piao>0;
			}
	}
	public void run() {
		 while(sale());
	}
}

部分出力:

synchronize(obj)の原理1.
各オブジェクトには内部ロック(組み込みロック)またはモニターロック(モニターロック)が関連付けられています
。2。同期ステートメントを実行する最初のスレッドは、内部ロックを取得し、実行後にロックを解放できます。同期ステートメント3のコード
。1つのスレッドが内部ロックを保持している限り、他のスレッドは同時にロックを取得できません
✓このロックを取得しようとすると、BLOCKED状態
4になります。複数の場合スレッドは同じsynchronized(obj)ステートメントにアクセスします。
同期を実現するには、objが同じオブジェクトである必要があります

スレッドの同期-同期方法

public class love implements Runnable{
    private int piao=3000;
    public synchronized boolean sale() { //synchronized作用于整个方法
            if(piao<1) return false;
            piao--;
            String sk =Thread.currentThread().getName();
            System.out.println(sk+"卖了1张票,还剩下"+piao+"张");
            return piao>0;
    }
    public void run() {
         while(sale());
    }
}


Synchronizedは、コンストラクター同期メソッドの本質を変更できません。
インスタンスメソッド:synchronized(this)
静的メソッド:synchronized(クラスオブジェクト)

同期されたステートメントは、同期されたメソッドよりも少し柔軟性があります。
同期されたステートメントは、ロックする必要のあるコードの範囲を正確に制御し、BLOCKED状態のスレッドの数を減らし、労力を最大限に活用できます。

スレッド同期技術を使用する
と、スレッドセーフの問題は解決しますが、プログラムの実行効率が低下します。
ロックを待機しているスレッドがあるため、ロックとロック解除の操作が多くなり、
本当に必要な場合にのみスレッドを使用してください。 。同期テクノロジー

おすすめ

転載: blog.csdn.net/weixin_59624686/article/details/124093334