Java基礎のよくある面接問題——ロック


1.synchronizedロックは原理を実現しますか?(ロック)と(synchronized)の違いは?
synchronizedは、方法またはコードブロックが動作している間、同じ時刻に一つの方法だけが臨界領域に入ることができます。同時に、共有変数のメモリ視認性も保証できます。synchronizedはjavaのmonitor機構で実装されています。synchronizedコードブロックまたは方法が入るときおよび退出するときに、monitonterとmonitoxitの二つのコマンドが生成されます。スレッドがmonitonterに実行されると、オブジェクトに対応するmonitorの所有権を取得しようとします。すなわち、取得しようとするオブジェクトのロックです。monit orexitはリリースロックです。Synchronizedはjava言語の中のヘビー級の操作です。Javaスレッドはオペレーティングシステムの元のスレッドに写像されています。ブロッキングまたはスレッドの起動には、オペレーティングシステムが必要です。ユーザー状態からコア状態に切り替える必要があります。変換には多くの処理時間がかかります。ユーザーコードの実行時間よりも長いかもしれません。仮想マシンはこれに対してスピンロックなどの最適化を行い,頻繁にコア状態に切り替えることを避けた。RentrantrantLockはRentrantrant LockとSynch ronizedと類似しています。一つはAPIレベルでの相互反発(lockとunlock方法)として表現されています。一つは元の文法レベルでの相互反発として表現されています。Reentrant LockはSynch ronizedに比べていくつかの高級機能を追加しました。①停止待ち:ロックを持っているスレッドが長い間ロックを解除しない(実行時間が長い同期ブロック)場合は、待ち時間のスレッドを選択して、他のことをすることができます。②公平ロックの実現:Rentrant Lockはデフォルトでは非公平であり、構造パラメータで公平ロックに設定できます。Synchronizedは非公平です。公平:申請の鍵をかける時間によって、先に来てもらって、整然としています。③ロックは複数の条件を結びつけることができます。jdk 1.6はロックの実現に大量の最適化を導入しており、例えばスピンロック、適応スピンロック、ロック除去、ロック粗化、バイアスロック、軽量級ロックなどの技術でロック操作のオーバーヘッドを低減している。
2.デッドロックとは?どうしてロックしますか?ロックが現れたらどうやって消しますか?
デッドロックとは、複数のプロセスが競争資源によって引き起こされる行き詰まり(互いに待つ)のことであり、外力の作用がないと、これらのプロセスは前に進められなくなります。例えば、プロセスAは対象1のロックを占有し、プロセスBは対象2のロックを占有し、プロセスAは対象2のロックを継続して実行することができるので、プロセスAはプロセスBのリリース対象2のロックを待つが、プロセスBは対象1のロックを継続して実行することが必要であり、同様にプロセスAのリリース対象1のロックを待つことができる。だから彼らが無限の待つ中に入ることを招いて融通がきかない鎖の原因を生みます:(1)システムの資源が足りないためです。(2)プロセス運行推進の順序が不適切である。(3)資源の配分が不適切などである。もしシステムの資源が十分であれば、プロセスの資源要求は全部満足できます。デッドロックが出現する可能性は低いです。そうでなければ、限られた資源を奪い合うためにデッドロックになります。次に、プロセスの進行順序と速度が違って、デッドロックが発生することもあります。デッドロックを発生する4つの必要条件:(1)相互反発条件:1つのリソースは毎回1つのプロセスでしか使用できない。(2)要求と保持条件:1つのプロセスがリソースを要求することによってブロックされた場合、獲得されたリソースに対してドロップしない。(3)条件を奪わない:プロセスによって得られた資源は、最終的に使用される前に、強制的に奪うことができない。(4)循環待ち条件:いくつかのプロセスの間に、首尾一貫した循環待ちリソース関係が形成される。この四つの条件はデッドロックの必要条件であり、システムがデッドロックが発生する限り、これらの条件は必ず成立します。上記の条件の一つが満たされない限り、デッドロックは発生しません。デッドロックの解除と予防:デッドロックの原因、特にデッドロックの4つの必要条件を理解すれば、最大で回避、予防と解除が可能です。したがって、システム設計、プロセススケジュールなどの面で、この4つの必要条件を成立させないように注意してください。また、プロセスが待ち状態にある場合に資源を占有することも防止しなければならない。したがって、資源の配分には合理的な計画が必要である。デッドロックを除去する3つの方法:1.最も簡単で、最も一般的な方法はシステムの再起動(価格が大きく、前の計算は無効)です。2.プロセスをキャンセルし、資源を剥奪する(一度に全部取消し、または逐次取消し、剥奪する)。3.プロセス返品ポリシー(プロセスをデッドロックのある時点または状態に戻す)。
3.シーンの問題:現在は三つのスレッドがありますが、同時にstartはどのような方法でスレッド実行の順序を保証できますか?スレッド1はスレッド2を実行し終わって、スレッド2はスレッド3を実行しますか?
ロックを取得する順番を指定し、指定された順番でロックを取得するように強制する簡単な方法。したがって、すべてのスレッドが同じ順番でロックとリリースロックをかけていると、デッドロックは発生しません。簡単に言えば、前のスレッドが実行済みであることを確認して、次のスレッドを実行することができます。法1:Thread.join()を呼び出し、Threadスレッドの実行が完了したことを確認する。法2:CountDownLatchでは、スレッド類を作成する際に、前のカウンタと本スレッドカウンタが入ります。運転前に前のカウンタ.await(前のスレッドは0で実行可能)を実行し、本カウンタ.count Down(本スレッドカウンタ減少)を実行します。下記のプログラム出力は?
public class TestSync2 implements Runnable {
    int b = 100;          
    synchronized void m1() throws InterruptedException {
        b = 1000;
        Thread.sleep(500); //6                  
        System.out.println("b=" + b);
    }
    synchronized void m2() throws InterruptedException {
        Thread.sleep(250); //5
        b = 2000;
    }
    public static void main(String[] args) throws InterruptedException {
        TestSync2 tt = new TestSync2();
        Thread t = new Thread(tt);  //1
        t.start(); //2
        tt.m2(); //3
        System.out.println("main thread b=" + tt.b); //4
}
    @Override
    public void run() {
        try {
            m1();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

  :main thread b=2000     main thread b=1000
b=1000                 b=1000
分析:javaは全部メーンメソッドから実行しました。上に2つのスレッドがあると言いましたが、ここでスレッド優先度を変更しても無駄です。優先順位は2つのプログラムがまだ実行されていない時に先着しています。現在このコードは実行されますと、メインスレッドmainはすでに実行されました。1ステップ実行時(Thread=new Thread)//1スレッドはnew状態で、まだ作業が開始されていません。2ステップを実行すると(t.start()//2)startメソッドを呼び出すと、このスレッドは本当に起動されています。runnable状態になり、runnable状態では実行できます。すべての準備は完了しましたが、必ずしもcpuの上で実行されるとは限りません。本当にサービスのcpuによるスケジュールが実行されていますか?ここで3ステップを実行すると必ず先にロックがかかります(startはnativeメソッドを呼び出す必要がありますので、完了後にすべての準備が完了しましたが、必ずしもcpuの上で実行されるとは限りません。本当にサービスcpuのスケジュールが実行されているかどうかは、後でrunメソッドを呼び出して、m 1方法を実行します)。ここは実は2つのsynchronized方法の中のThread.sheepは大丈夫ですか?3ステップ実行時には子スレッドも用意されていますが、synchronizedが存在していますので、同じ対象となりますので、子スレッドは待つしかありません。メインメソッドでは、実行順序が順次実行されるため、ステップ3の実行が完了してから4ステップまででなければなりませんが、3ステップの実行が完了したため、サブスレッドはm 1を実行することができます。ここではマルチスレッドが存在します。4ステップで先に取得したら、メインストリームb=2000です。サブスレッドm 1を取得したら、bはすでに1000になりました。または4ステップの値を付与していないと出力されます。結果として、main thread b=1000またはmain thread b=2000となります。ここで6ステップを外したらb=実行前とmain thread b=前は確定しません。しかし、6ステップがあるので、どうしてもメーンthread b=前であれば、1000に等しいか2000に等しいかどうかは、次のb=1000は一定です。