インタビューの質問:2つのプロデューサースレッドと10のコンシューマースレッドのブロック呼び出しをサポートできる、putメソッドとgetメソッドを使用して固定容量の同期コンテナーを作成します

1synchronized + wait()+ notifyAllで実現

アイデア:プロデューサーが最大数に達したら、プロデューサースレッドにブロックと待機を待機させます。それ以外の場合は、プロデュースを続行し、同時にコンシューマーに消費するように通知します。

           コンシューマーが0を消費する場合、コンシューマースレッドをブロックして待機するまで待機させます。それ以外の場合は消費を継続し、同時にプロデューサーに生成を通知します。

パブリッククラスContainer1 <T> {

    最終プライベートLinkedList <T>リスト=新しいLinkedList <T>(); 

    final private int MAX = 10; //最多10要素privateint 

    count = 0; 

    public synchronized void put(T t){ 
        while(lists.size()== MAX){ 
            try { 
                this.wait(); 
            } catch(InterruptedException e){ 
                e.printStackTrace(); 
            } 
        } 

        lists.add(t); 
        ++カウント; 
        this.notifyAll(); //消費消费者ワイヤー程の行消费

    } 


    public synchronized T get(){ 
        T t = null; 
        while(lists.size()== 0){ 
            try {
                this.wait(); 
            } catch(InterruptedException e){ 
                e.printStackTrace(); 
            } 
        } 
        t = lists.removeFirst(); 
        カウント - ; 
        this.notifyAll(); //通知生生産者進行行生生産returnt 
        ; 
    } 


    public static void main(String [] args){ 
        Container1 <String> c = new Container1 <>(); 
        //启PIN消费者線程
        for(int i = 0; i <10; i ++){ 
            new Thread(()-> { 
                for(int j = 0; j <5; j ++){ 
                    System.out.println(Thread。 currentThread()。getName()+ "get =" + c.get()); 
                } 
            }、 "c" + i).start(); 
        }

        試してください{ 
            TimeUnit.SECONDS.sleep(2); 
        } catch(InterruptedException e){ 
            e.printStackTrace(); 
        } 

        // 
        (int i = 0;のプロデューサースレッド開始しますi <2; i ++){ 
            new Thread(()-> { 
                for(int j = 0; j <25; j ++){ 
                    c.put(Thread.currentThread()。getName()+ "set =" + j) ; 
                } 
            }、 "p" + i).start(); 
        } 

    } 

}

この実装には問題があります。プロデューサースレッドがnotifyAll通知を呼び出すと、プロデューサースレッドに通知する場合があり、コンシューマースレッドはnotifyAll通知を呼び出します。その時点でコンシューマスレッドに通知することが可能であるため、改善することができます。この問題を解決するために、以下の2番目の方法を使用します。

 

2ロックとコンディションを使用して

ロック処理を実行するときのインターフェースもあります条件。このインターフェースは、ユーザーがロックのオブジェクトを作成するために作成できます。

Conditionの機能は、ロックをより正確に制御することです。

await()のメソッドの条件があると同等ウエイト()のメソッドオブジェクト信号()のメソッド条件であると同等の通知()のメソッドオブジェクト、及びsignalAll()のメソッド条件であると同等(のnotifyAll )オブジェクトのメソッド。

違いは、Objectwait()、notify()、notifyAll() メソッドが同期ロック」(同期キーワード)と組み合わせて使用​​されるのに対し、Conditionは「相互排他ロック/共有ロック」と組み合わせて使用​​する必要があることです。

条件を使用して、2つの待機キューを使用して、それぞれプロデューサーキューとコンシューマーキューを実装します

パブリッククラスContainer2 <T> {


    最終プライベートLinkedList <T>リスト=新しいLinkedList <>(); 
    final private int MAX = 10; //最多10要素privateint 
    count = 0; 

    プライベートロックロック= new ReentrantLock(); 

    プライベート条件プロデューサー= lock.newCondition(); 
    プライベート条件consumber = lock.newCondition(); 

    public void put(T t){ 
        try { 
            lock.lock(); 
            while(lists.size()== MAX){ 

                producer.await(); 

            } 
            lists.add(t); 
            ++カウント; 
            consumber.signalAll(); //消費消费者スレッド程の行消费
        } catch(InterruptedException e){
            e.printStackTrace(); 
        } 最後に {
            施錠開錠(); 
        } 
    } 

    public T get(){ 
        T t = null; 
        { 
            lock.lock();を試してください
            while(lists.size()== 0){ 
                consumber.await(); 
            } 
            t = Lists.removeFirst(); 
            カウント - ; 
            producer.signalAll(); //生産生生産者追跡生プログラム
        } catch(InterruptedException e){ 
            e.printStackTrace(); 
        }最後に{ 
            lock.unlock(); 
        } 
        return t; 
    } 
 
    public static void main(String [] args){
        Container2 c = new Container2(); 
        for(int i = 0; i <10; i ++){
            new Thread(()-> { 
                for(int j = 0; j <5; j ++){ 
                    System.out.println(Thread.currentThread()。getName()+ "get =" + c.get()); 
                } 
            }、 "c" + i).start(); 
        } 

        try { 
            TimeUnit.SECONDS.sleep(2); 
        } catch(InterruptedException e){ 
            e.printStackTrace(); 
        } 

        //启PIN生生産者ワイヤー程
        for(int i = 0; i <2; i ++){ 
            new Thread(()-> { 
                for(int j = 0; j <25; j ++){ 
                    c.put(Thread.currentThread ().getName()+ "set =" + j);
            }、 "p" + i).start(); 
        }



}

おすすめ

転載: blog.csdn.net/huzhiliayanghao/article/details/106658257