検索
ホームページJava&#&ベースJava ではロックとプロデューサー/コンシューマーの問題が発生します

Java ではロックとプロデューサー/コンシューマーの問題が発生します

無料学習の推奨事項: Java 基本チュートリアル

ロック ロックとプロデューサー/コンシューマーの問題

  • 従来の同期ロック
  • ロック ロック
  • 同期ロックとロック ロックの違い
  • 従来のプロデューサーとコンシューマの問題
  • プロデューサとコンシューマの問題のロック バージョン
  • 正確な通知ウェイクアップを実現するための条件

従来の同期ロック

基本的なチケット販売の例を実装します:

/*
真正的多线程开发,公司中的开发,降低耦合性
线程就是一个单独的资源类,没有任何附属的操作
1.属性,方法
 * */public class SaleTicketDemo1 {
    public static void main(String[] args) {
        //并发,多个线程操作同一个资源类,把资源类丢入线程
        Ticket ticket=new Ticket();
        //Runnable借口是一个FunationalInterface函数式接口,接口可以new,jdk1.8以后,lamda表达式()->{代码}
        new Thread(()->{
            for(int i=0;i{
            for(int i=0;i0){
            System.out.println(Thread.currentThread().getName()+"卖出了"+(number--)+"票,剩余"+number);
        }
    }}

ここではラムダ式が使用されていることに注意してください。ラムダ式の詳細な説明については、「Java の基礎 - ラムダ式」を参照してください

Java ではロックとプロデューサー/コンシューマーの問題が発生します
これは、同時実行性を実現するために従来の同期を使用することです。同期の本質はキューとロックです。カフェテリアに並ぶようなものです。行列がないと混乱してしまいます。一人へのサービスが完了して初めて、他の人もサービスを受けることができます。

Lock

前述したように、JVM は変数への同期アクセスを実現し、wait と notification を使用してスレッド間通信を実装するための synchronized キーワードを提供します。 jdk1.5以降、JAVAではsynchronizedと同様の機能を実装するためのLockクラスが提供され、またスレッド間の通信を表示するためのConditionも提供されています。
Lock クラスは Java クラスが提供する機能であり、豊富な API により Lock クラスの同期機能は同期よりも強力です。
java.util.Concurrent パッケージには、Condition と lock (標準ロック) の 3 つのインターフェイスがあります。 ReadWriteLock ロック (読み取り/書き込みロック)
Lock 実装は、同期されたメソッドやステートメントを使用して取得できるよりも広範囲のロック操作を提供します。これらにより、より柔軟な構造化が可能になり、完全に異なるプロパティを持つことができ、関連する複数のオブジェクト条件をサポートできます。

Lock l = ...; l.lock(); try { // access the resource protected by this lock } finally { l.unlock(); }

lock() はロック、unlock() はロック解除を意味します
JDK 公式ドキュメントで説明されています
Java ではロックとプロデューサー/コンシューマーの問題が発生します
すべて既知の実装クラス:
ReentrantLock リエントラント ロック
ReentrantReadWriteLock.ReadLock 読み取りロック
ReentrantReadWriteLock.writeLock 書き込みロック

まず、ReentrantLock 実装クラスについて説明します。 :
ReentrantLock の基礎となるソース コード コンストラクター
Java ではロックとプロデューサー/コンシューマーの問題が発生します
公平なロック: 非常に公平で、早い者勝ちです。しかし問題は、3s と 3h のプロセスが到着した場合、3h が最初に来て、その後 3s が 3h 待機することですが、これは実際には良くありません。
不公平なロック: 非常に不公平です。キューをジャンプできます (デフォルト)
これについては後で詳しく説明します。

使い方、使用前ロック、使用後のロック解除

//ロックロックトリロジー
//1.new ReentranLock() ;構築
//2.Lock.lock();Lock
//3.finally();Unlock

public class SaleTicketDemo2 {
	public static void main(String[] args) {
		//并发,多个线程操作同一个资源类,把资源类丢入线程
		Ticket ticket=new Ticket();
		//Runnable借口是一个FunationalInterface函数式接口,接口可以new,jdk1.8以后,lamda表达式()->{代码}
		new Thread(()->{for(int i=0;i{for(int i=0;i{for(int i=0;i0){
				System.out.println(Thread.currentThread().getName()+"卖出了"+(number--)+"票,剩余"+number);
			}
		} catch (Exception e) {
			// TODO: handle exception
		}finally{
			lock.unlock();
		}	
	}}

Synchronized と lock lock の違い

1.synchronized は組み込みの Java キーワード、lock は Java クラスです
2.synchronized はロックの取得ステータスを判断できません、lock はロックが取得されたかどうかを判断できます
3.同期は自動的に行われます。ロックを解除するには (a-)、手動でロックを解除する必要があります。ロックが解放されない場合、デッドロックが発生します。
4. 同期スレッド 1 (ロックの取得、ブロック)、スレッド 2 (待機、愚かな待機)
lock.tryLock() はロックの取得を試みますが、常に起こるとは限りません。お待ちください
5. 同期された再入可能なロック、中断できない不公平なロック。ロック、リエントラントロック、ロックを判定可能、公平・不公平を自分で設定可能(自分で設定可能)
6. synchronized は少量のコード同期問題に適し、lock lock は大量のコード同期の問題に適しています。同期されたコードの量
同期されたロック オブジェクトと同期されたコード ブロック メソッド

従来のプロデューサーとコンシューマーの問題

従来のプロデューサーとコンシューマーは待機通知メソッドに基づいていますこれを実現するために、オブジェクト クラスのワードと同期キーが使用されます。
面接中に、プロデューサーとコンシューマーのコードを手書きすることは非常に一般的です。
面接筆記試験の古典的な質問:
シングルトン モードの並べ替えアルゴリズム プロデューサーとコンシューマーのデッドロック
プロデューサーとコンシューマーの問題の同期バージョン

スレッド間の通信の問題: プロデューサー ウェイク待ち-up with Consumer issues, notification wake-up
スレッドは同じ変数を操作するために A B を交互に実行します。number=0
A num 1
B num-1

注: はlocked メソッドでは、業務通知を判断して待つという実行の考え方です。

package testConcurrent;/*
线程之间的通信问题:生产者和消费者问题    等待唤醒,通知唤醒
线程交替执行 A B 操作同一个变量number=0
A num+1
B num-1

 * */public class A {
	public static void main(String[] args) {
		Data data =new Data();
		new Thread(()->{
			for(int i=0;i{
			for(int i=0;i"+number);
		//通知其他线程,我+1完毕了
		this.notify();
	}
	//-1
	public synchronized void decrement() throws InterruptedException{
		if(number==0){
			//等待
			this.wait();
		}
		number--;
		System.out.println(Thread.currentThread().getName()+"=>"+number);
		//通知其他线程,我-1完毕了
		this.notify();
	}}

Java ではロックとプロデューサー/コンシューマーの問題が発生します
図に示すように、基本的に必要な機能は実現できますただし、問題は引き続き発生します。この時点で 2 つのスレッドを追加して再試行すると、

		new Thread(()->{
			for(int i=0;i{
			for(int i=0;i<p><img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/000/052/4011c6e510a595c0afc39326e031cf33-4.png?x-oss-process=image/resize,p_40" class="lazy" alt="Java ではロックとプロデューサー/コンシューマーの問題が発生します"><br> 这里结果中出现了2,输出结果出现了问题。为什么呢?<br> 为什么if判断会出现问题:<br> if判断只判断一次。因为if判断了之后,就已经进入了代码的等待那一行,这时,在wait下的线程可能有多个,甚至包括生产者和消费者。有可能某个生产者执行完了之后,唤醒的是另一个生产者。</p><p>在我们的官方文档中就给出了解释</p><pre class="brush:php;toolbar:false">public final void wait(long timeout)
                throws InterruptedException

导致当前线程等待,直到另一个线程调用此对象的notify()方法或notifyAll()方法,或指定的时间已过。
线程也可以唤醒,而不会被通知,中断或超时,即所谓的虚假唤醒 。 虽然这在实践中很少会发生,但应用程序必须通过测试应该使线程被唤醒的条件来防范,并且如果条件不满足则继续等待。 换句话说,等待应该总是出现在循环中,就像这样:

 synchronized (obj) {
         while (<condition>)
             obj.wait(timeout);
         ... // Perform action appropriate to condition
     }</condition>

注意点:防止虚假唤醒问题
我们代码中用的是if判断,而应该用while判断

package testConcurrent;/*
线程之间的通信问题:生产者和消费者问题    等待唤醒,通知唤醒
线程交替执行 A B 操作同一个变量number=0
A num+1
B num-1

 * */public class A {
    public static void main(String[] args) {
        Data data =new Data();
        new Thread(()->{
            for(int i=0;i{
            for(int i=0;i{
            for(int i=0;i{
            for(int i=0;i"+number);
        //通知其他线程,我+1完毕了
        this.notify();
    }
    //-1
    public synchronized void decrement() throws InterruptedException{
        while(number==0){
            //等待
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName()+"=>"+number);
        //通知其他线程,我-1完毕了
        this.notify();
    }}

Lock版的生产者和消费者问题

在synchronized版本中,我们使用了wait和notify来实现线程之间的同步
在lock中,
此时synchronized被lock替换了,那么wait和notify用什么来替换呢?
我们在官方文档java.util.concurrent.locks 中,找到Lock类,然后在底部找到了
Condition newCondition()
返回一个新Condition绑定到该实例Lock实例。
在等待条件之前,锁必须由当前线程保持。 呼叫Condition.await()将在等待之前将原子释放锁,并在等待返回之前重新获取锁。

然后我们再来了解Condition类
Condition 将 Object 监视器方法(wait、notify 和 notifyAll)分解成截然不同的对象,以便通过将这些对象与任意 Lock 实现组合使用,为每个对象提供多个等待 set(wait-set)。其中,Lock 替代了 synchronized 方法和语句的使用,Condition 替代了 Object 监视器方法的使用。
一个Condition实例本质上绑定到一个锁。 要获得特定Condition实例的Condition实例,请使用其newCondition()方法。

Java ではロックとプロデューサー/コンシューマーの問題が発生します
我们可以看到,使用的时候new一个Condition对象。然后用await替代wait,signal替换notify
代码实现
//判断等待+业务+通知

class Data2{		//数字。资源类
	private int number=0;
	Lock lock=new ReentrantLock();
	Condition condition=lock.newCondition();
	//+1
	public void increment() throws InterruptedException{
		try {
			lock.lock();
			//业务代码
			while(number!=0){		
				//等待
				condition.await();
			}
			number++;		
			System.out.println(Thread.currentThread().getName()+"=>"+number);
			condition.signalAll();		//通知
		} catch (Exception e) {
			// TODO: handle exception
		}finally{
			lock.unlock();
		}
	}
	//-1
	public void decrement() throws InterruptedException{
		try {
			lock.lock();
			//业务代码
			while(number!=1){		
				//等待
				condition.await();
			}
			number--;		
			System.out.println(Thread.currentThread().getName()+"=>"+number);
			condition.signalAll();		//通知
		} catch (Exception e) {
			// TODO: handle exception
		}finally{
			lock.unlock();
		}
	}	}

注意:主函数部分于最上面的代码一样。

Java ではロックとプロデューサー/コンシューマーの問題が発生します
这时候虽然说是正确的,但是它是一个随机分布的状态,现在我们希望它有序执行,即A执行完了执行B,B执行C,C完了执行D。即精准通知。

Condition实现精准通知唤醒

Condition实现精准的通知和唤醒
我们构造三个线程,要求A执行完了执行B,B执行完了执行C,C执行完了执行D.
代码思想:
//加多个监视器,通过监视器来判断唤醒的是哪一个人
//设置多个同步监视器,每个监视器监视一个线程
//实例:生产线,下单->支付->交易->物流

package testConcurrent;import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;/*
A执行完调用B,B执行完调用C,C执行完调用A
 * */public class C {

    public static void main(String[] args) {
        Data3 data=new Data3();
        new Thread(()->{
            for(int i=0;i{
            for(int i=0;i{
            for(int i=0;i支付->交易->物流
    private Condition condition1=lock.newCondition();
    private Condition condition2=lock.newCondition();
    private Condition condition3=lock.newCondition();
    private int number=1;       //1A 2B 3C
    public void printA(){
        lock.lock();
        try {
            //业务,判断->执行->通知
            while(number!=1){
                //等待
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>AAAAAAA");
            //唤醒,唤醒指定的人,B
            number=2;           //精准唤醒
            condition2.signal();
            
        } catch (Exception e) {
            // TODO: handle exception
        }finally{
            lock.unlock();
        }
    }   
    public void printB(){
        lock.lock();
        try {
            //业务,判断->执行->通知
            while(number!=2){
                //等待
                condition2.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>BBBBBBB");
            //唤醒,唤醒指定的人,C
            number=3;           //精准唤醒
            condition3.signal();
            
        } catch (Exception e) {
            // TODO: handle exception
        }finally{
            lock.unlock();
        }
    }
    public void printC(){
        lock.lock();
        try {
            //业务,判断->执行->通知
            while(number!=3){
                //等待
                condition3.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>CCCCCCC");
            //唤醒,唤醒指定的人,A
            number=1;           //精准唤醒
            condition1.signal();
            
        } catch (Exception e) {
            // TODO: handle exception
        }finally{
            lock.unlock();
        }
    }}

相关学习推荐:java基础

以上がJava ではロックとプロデューサー/コンシューマーの問題が発生しますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明
この記事はCSDNで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。
Java(シリアル、パラレル、CMS、G1、ZGC)のごみ収集アルゴリズムは何ですか?Java(シリアル、パラレル、CMS、G1、ZGC)のごみ収集アルゴリズムは何ですか?Mar 14, 2025 pm 05:06 PM

この記事では、さまざまなJava Garbage Collectionアルゴリズム(シリアル、パラレル、CMS、G1、ZGC)、そのパフォーマンスへの影響、および大きなヒープを持つアプリケーションの適合性について説明します。

Java Virtual Machine(JVM)とは何ですか?内部でどのように機能しますか?Java Virtual Machine(JVM)とは何ですか?内部でどのように機能しますか?Mar 14, 2025 pm 05:05 PM

この記事では、Java Virtual Machine(JVM)について説明し、さまざまなプラットフォームでJavaプログラムを実行する際の役割について詳しく説明しています。 JVMの内部プロセス、主要コンポーネント、メモリ管理、ガベージコレクション、およびパフォーマンスの最適化について説明します

JavaScriptを使用したスクリプトにJavaのナショーンエンジンを使用するにはどうすればよいですか?JavaScriptを使用したスクリプトにJavaのナショーンエンジンを使用するにはどうすればよいですか?Mar 14, 2025 pm 05:00 PM

Javaのナショーンエンジンは、Javaアプリ内でJavaScriptスクリプトを可能にします。重要な手順には、ナショーンのセットアップ、スクリプトの管理、パフォーマンスの最適化が含まれます。主な問題には、ナショーンのdeprecによるセキュリティ、記憶管理、将来の互換性が含まれます

自動リソース管理にJavaのリソース付きステートメントを使用するにはどうすればよいですか?自動リソース管理にJavaのリソース付きステートメントを使用するにはどうすればよいですか?Mar 14, 2025 pm 04:59 PM

Javaのリソースでの試行は、ファイルストリームやデータベース接続などのリソースを自動的に閉じることでリソース管理を簡素化し、コードの読みやすさと保守性を向上させます。

Javaの酵素を使用して固定値のセットを表すにはどうすればよいですか?Javaの酵素を使用して固定値のセットを表すにはどうすればよいですか?Mar 14, 2025 pm 04:57 PM

Java Enumsは、固定された値のセットを表し、カスタムメソッドとコンストラクターを介してタイプの安全性、読みやすさ、および追加の機能を提供します。それらはコード組織を強化し、効率的なバリューハンドリングのためにスイッチステートメントで使用できます。

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

EditPlus 中国語クラック版

EditPlus 中国語クラック版

サイズが小さく、構文の強調表示、コード プロンプト機能はサポートされていません

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SecLists

SecLists

SecLists は、セキュリティ テスターの究極の相棒です。これは、セキュリティ評価中に頻繁に使用されるさまざまな種類のリストを 1 か所にまとめたものです。 SecLists は、セキュリティ テスターが必要とする可能性のあるすべてのリストを便利に提供することで、セキュリティ テストをより効率的かつ生産的にするのに役立ちます。リストの種類には、ユーザー名、パスワード、URL、ファジング ペイロード、機密データ パターン、Web シェルなどが含まれます。テスターはこのリポジトリを新しいテスト マシンにプルするだけで、必要なあらゆる種類のリストにアクセスできるようになります。

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

このプロジェクトは osdn.net/projects/mingw に移行中です。引き続きそこでフォローしていただけます。 MinGW: GNU Compiler Collection (GCC) のネイティブ Windows ポートであり、ネイティブ Windows アプリケーションを構築するための自由に配布可能なインポート ライブラリとヘッダー ファイルであり、C99 機能をサポートする MSVC ランタイムの拡張機能が含まれています。すべての MinGW ソフトウェアは 64 ビット Windows プラットフォームで実行できます。

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強力な PHP 統合開発環境