マルチスレッドの印刷結果を順番に

序文

このテキストは私のGitHubリポジトリに含まれています。スターへようこそ:github.com/bin39232820 ...
木を植えるのに最適な時期は10年前、そして今が続きます。
多くの人がqqをプレイしないことを知っていますが、ノスタルジア、6つに参加することを歓迎しますパルスエクスカリバーJavaルーキーラーニンググループ、グループチャット番号:549684836テクノロジーへの道のりをブログで紹介する

おしゃべり

これは非常に単純なマルチスレッドの問題ですが、Primary SixとSixでは非常に単純に見えますが、書くのはそれほど簡単ではなく、Primary SixまたはSixの独自のコードがまだほとんど書かれていないことを示しています

タイトル

私たちはクラスを提供します:

public class Foo {
  public void one() { print("one"); }
  public void two() { print("two"); }
  public void three() { print("three"); }
}
复制代码

3つの異なるスレッドがFooインスタンスを共有します。

  • スレッドAが1つの()メソッドを呼び出す
  • スレッドBはtwo()メソッドを呼び出します
  • スレッドCは3つの()メソッドを呼び出します

two()メソッドがone()メソッドの後に実行され、three()メソッドがtwo()メソッドの後に実行されるようにプログラムを設計および変更してください。

例1:

输入: [1,2,3]
输出: "onetwothree"
解释: 
有三个线程会被异步启动。
输入 [1,2,3] 表示线程 A 将会调用 one() 方法,线程 B 将会调用 two() 方法,线程 C 将会调用 three() 方法。
正确的输出是 "onetwothree"复制代码

問題1:同期されたロックと制御変数

package com.code.thread;

/**
 * 上面方法就是采用一个synchronized wait notifyAll  这些来实现的,但是吧,还需要一个while去自旋,还得靠一个信号量,感觉有点low。
 */

class Foo {

    private  int flag=0;
    private Object lock=new Object();
    public Foo() {

    }

    public void first(Runnable printFirst) throws InterruptedException {
        synchronized(lock){
            while (flag!=0){
                lock.wait();
            }
            // printFirst.run() outputs "first". Do not change or remove this line.
            printFirst.run();
            flag=1;
            lock.notifyAll();
        }

    }

    public void second(Runnable printSecond) throws InterruptedException {
        synchronized (lock) {
            while (flag != 1) {
                lock.wait();
            }
            // printSecond.run() outputs "second". Do not change or remove this line.
            printSecond.run();
            flag = 2;
            lock.notifyAll();
        }
    }

    public void third(Runnable printThird) throws InterruptedException {
        synchronized(lock) {
            while (flag != 2) {
                lock.wait();
            }
            // printThird.run() outputs "third". Do not change or remove this line.
            printThird.run();
            lock.notifyAll();
        }
    }

    public static void main(String[] args) throws Exception {
        final Foo foo = new Foo();

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    foo.first(new Runnable() {
                        @Override
                        public void run() {
                            System.out.println(1);
                        }
                    });
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    foo.second(new Runnable() {
                        @Override
                        public void run() {
                            System.out.println(2);
                        }
                    });
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    foo.third(new Runnable() {
                        @Override
                        public void run() {
                            System.out.println(3);
                        }
                    });
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t3.start();
        t2.start();
        t1.start();

    }
}

复制代码

上記のメソッドは、同期された待機notifyAllを使用して実装されていますが、スピンするにはしばらく時間がかかりますが、セマフォに依存しているため、少し低く感じられます。

問題2はCountDownLatchを使用して制御します

  • countDownLatchクラスは、スレッドが他のスレッドが実行を完了する前に実行を完了するのを待ちます。
  • カウンタにより実現され、カウンタの初期値はスレッド数です。スレッドの実行が終了するたびに、カウンターの値は-1になります。カウンターの値が0の場合は、すべてのスレッドが実行を終了し、ロックを待機しているスレッドが作業を再開できることを意味します。
package com.code.thread;

import java.util.concurrent.CountDownLatch;

public class Foo1 {
    //定义2个countDownLatch
    private CountDownLatch countDownLatchA=new CountDownLatch(1); //说明只要一个线程调用它就放行 ,它是到0就放行
    private CountDownLatch countDownLatchB=new CountDownLatch(1);
    public Foo1() {

    }

    public void first(Runnable printFirst) throws InterruptedException {
            // printFirst.run() outputs "first". Do not change or remove this line.
            printFirst.run();


    }

    public void second(Runnable printSecond) throws InterruptedException {
            // printSecond.run() outputs "second". Do not change or remove this line.
            printSecond.run();

    }

    public void third(Runnable printThird) throws InterruptedException {
            // printThird.run() outputs "third". Do not change or remove this line.
        printThird.run();

    }

    public static void main(String[] args) throws Exception {
        final Foo1 foo = new Foo1();

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    foo.first(new Runnable() {
                        @Override
                        public void run() {
                            System.out.println(1);
                        }
                    });
                    foo.countDownLatchA.countDown();

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    foo.countDownLatchA.await();
                    foo.second(new Runnable() {
                        @Override
                        public void run() {
                            System.out.println(2);
                        }
                    });
                    foo.countDownLatchB.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        });
        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                    try {
                        foo.countDownLatchB.await();
                        foo.third(new Runnable() {
                            @Override
                            public void run() {
                                System.out.println(3);
                            }
                        });
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
            }
        });
        t3.start();
        t2.start();
        t1.start();

    }
}

复制代码

方法3セマフォ

セマフォベースの問題解決のアイデア

  • セマフォとは?
  • セマフォは、それを取得したスレッドによって解放される必要があるカウントセマフォです。
package com.code.thread;

import java.util.concurrent.Semaphore;

/**
 *
 * 基于信号量的解题思路
 * Semaphore 是什么?
 * Semaphore 是一个计数信号量,必须由获取它的线程释放。
 *
 * 常用于限制可以访问某些资源的线程数量,例如通过 Semaphore 限流。
 */
public class Foo2 {

    //初始化Semaphore为0的原因:
    // 如果这个Semaphore为零,如果另一线程调用(acquire)这个Semaphore就会产生阻塞,
    // 便可以控制second和third线程的执行
    private Semaphore spa=new Semaphore(0) ;
    private Semaphore spb=new Semaphore(0);




    public Foo2() {

    }

    public void first(Runnable printFirst) throws InterruptedException {

        printFirst.run();
        spa.release();
    }

    public void second(Runnable printSecond) throws InterruptedException {
        // printSecond.run() outputs "second". Do not change or remove this line.
        spa.acquire();
        printSecond.run();
        spb.release();
    }

    public void third(Runnable printThird) throws InterruptedException {
        // printThird.run() outputs "third". Do not change or remove this line.
        spb.acquire();
        printThird.run();
    }

    public static void main(String[] args) throws Exception {
        final Foo2 foo = new Foo2();

        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    foo.first(new Runnable() {
                        @Override
                        public void run() {
                            System.out.println(1);
                        }
                    });
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    foo.second(new Runnable() {
                        @Override
                        public void run() {
                            System.out.println(2);
                        }
                    });
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    foo.third(new Runnable() {
                        @Override
                        public void run() {
                            System.out.println(3);
                        }
                    });
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t3.start();
        t2.start();
        t1.start();

    }
}

复制代码

問題解決4 LockSupport

最終的な分析では、UnsafeのネイティブコードがLockSupportによって呼び出されます。

  • パブリックネイティブvoid unpark(Thread jthread);
  • public native void park(boolean isAbsolute、long time);
  • 2つの関数宣言は操作オブジェクトを明確に説明しています。park関数は現在のスレッドをブロックするもので、unpark関数は別のスレッドをウェイクアップするものです。
package com.code.thread;

import java.util.concurrent.locks.LockSupport;

/**'
 * 归根结底,LockSupport调用的Unsafe中的native代码:
 * public native void unpark(Thread jthread);
 * public native void park(boolean isAbsolute, long time);
 * 两个函数声明清楚地说明了操作对象:park函数是将当前Thread阻塞,而unpark函数则是将另一个Thread唤醒。
 *
 * 与Object类的wait/notify机制相比,park/unpark有两个优点:1. 以thread为操作对象更符合阻塞线程的直观定义;2. 操作更精准,可以准确地唤醒某一个线程(notify随机唤醒一个线程,notifyAll唤醒所有等待的线程),增加了灵活性。
 */
public class Foo3 {
    static Thread t1=null,t2=null,t3=null;

    public Foo3() {

    }

    public void first(Runnable printFirst) throws InterruptedException {

        printFirst.run();
    }

    public void second(Runnable printSecond) throws InterruptedException {
        // printSecond.run() outputs "second". Do not change or remove this line.
        printSecond.run();
    }

    public void third(Runnable printThird) throws InterruptedException {
        // printThird.run() outputs "third". Do not change or remove this line.
        printThird.run();
    }


        public static void main(String[] args) throws Exception {
            final Foo3 foo = new Foo3();

             t1 = new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        foo.first(new Runnable() {
                            @Override
                            public void run() {
                                System.out.println(1);
                            }
                        });
                        LockSupport.unpark(t2);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
             t2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    LockSupport.park();
                    try {
                        foo.second(new Runnable() {
                            @Override
                            public void run() {
                                System.out.println(2);
                            }
                        });
                        LockSupport.unpark(t3);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
             t3 = new Thread(new Runnable() {
                @Override
                public void run() {
                    LockSupport.park();
                    try {
                        foo.third(new Runnable() {
                            @Override
                            public void run() {
                                System.out.println(3);
                            }
                        });
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            t3.start();
            t2.start();
            t1.start();

    }
}
复制代码

終わり

実際、多くのソリューションがありますが、マルチスレッドに慣れていない場合は、私のgithubブログにアクセスして、最初に慣れることができます。この質問は、単純な質問タイプと見なす必要があります。

毎日の賞賛

さて皆さん、上記はこの記事の全内容ですここの人々を見ることができますすべて真のファンです。

作成は簡単ではありません。あなたのサポートと認識が私の作成の最大の動機です。次の記事でお会いしましょう。

リウマイエクスカリバー|テキスト[オリジナル]このブログにエラーがある場合は、批判して指示してください、ありがとうございます!

おすすめ

転載: juejin.im/post/5e999ff0518825738e2180e0