2019年Java面接問題基礎シリーズ228道(4)

8727 ワード

1、Javaでvolatile配列を作成できますか?
はい、Javaではvolatileタイプの配列を作成できますが、配列全体ではなく配列を指す参照にすぎません.参照が指す配列を変更するとvolatileによって保護されますが、複数のスレッドが配列の要素を同時に変更すると、volatileマーカーは以前の保護の役割を果たすことができません.
2、volatileは1つの非原子操作を原子操作に変えることができますか?
典型的な例は、クラスにlongタイプのメンバー変数があることです.カウンタ、価格など、メンバー変数が複数のスレッドにアクセスされることを知っている場合は、volatileに設定したほうがいいです.どうして?Javaでlongタイプ変数を読み取るのは原子ではないので、2つのステップに分ける必要があります.1つのスレッドがlong変数の値を変更している場合、別のスレッドはその値の半分(上位32ビット)しか見えない可能性があります.しかし、1つのvolatile型のlongまたはdouble変数の読み書きは元の子です.
3、volatile修飾子の実践は何ですか.
1つの実践はvolatileでlongとdouble変数を修飾し、原子タイプで読み書きできるようにすることである.doubleとlongはいずれも64ビット幅であるため、この2つのタイプの読み取りは2つの部分に分かれており、最初の32ビットを初めて読み取り、残りの32ビットを読み返す過程は原子ではないが、Javaにおけるvolatile型のlongまたはdouble変数の読み書きは原子である.volatileリペアのもう一つの役割は、分散フレームワークなどのメモリバリアを提供することです.簡単に言えば、volatile変数を書く前にJavaメモリモデルが書き込みバリア(writebarrier)を挿入し、volatile変数を読む前に読み取りバリアを挿入します.(read barrier).つまり、volatil eドメインを書くと、任意のスレッドがあなたの書いた値を見ることができることを保証します.また、書く前に、メモリバリアが他のすべての書いた値をキャッシュに更新するため、任意の数値の更新がすべてのスレッドに表示されることを保証します.
4、volatileタイプ変数はどんな保証を提供しますか?
volatile変数は順序と可視性の保証を提供します.たとえば、JVMまたはJITはより良いパフォーマンスを得るために文を並べ替えますが、volatileタイプ変数は同期ブロックがなくても他の文と並べ替えられません.volatileはhappens-beforeの保証を提供し、1つのスレッドの修正が他のスレッドに表示されることを保証します.場合によっては、volatileは64ビットのデータ型を読むなど、longやdoubleは原子ではありませんが、volatileタイプのdoubleとlongは原子です.
5、10スレッドと2スレッドの同期コード、どちらが書きやすいですか?
コードを書く観点から、同期コードとスレッドの数は互いに独立しているため、両者の複雑さは同じである.しかし、同期ポリシーの選択はスレッドの数に依存します.多くのスレッドはより大きな競争を意味するため、ロック分離などの同期技術を利用する必要があります.これは、より複雑なコードと専門知識を必要とします.
6、wait()メソッドをどのように呼び出しますか?ifブロックを使用しますか?それともループを使用しますか?なぜですか?
wait()メソッドは、スレッドがCPUを取得して実行を開始すると、他の条件が満たされていない可能性があるため、処理前にループ検出条件が満たされているかどうかがより良い.次に、waitメソッドとnotifyメソッドを使用する標準的なコードを示します.
// The standard idiom for using the wait methodsynchronized (obj) {
    while (condition does not hold)
    obj.wait();
    // (Releases lock, and reacquires on wakeup)
    ... // Perform action appropriate to condition}

7、マルチスレッド環境での擬似共有(false sharing)とは?
擬似共有は、マルチスレッドシステム(各プロセッサに独自のローカルキャッシュがある)でよく知られているパフォーマンスの問題です.擬似共有は、異なるプロセッサで発生するスレッドの変数に対する変更が同じキャッシュラインに依存します.
8、Busy spinとは何ですか.なぜそれを使うのですか?
Busy spinは、CPUを解放せずにイベントを待つ技術である.CPUキャッシュ内のデータの損失を回避するためによく使用されます(スレッドが一時停止すると、他のCPUで実行されると失われます).したがって、作業に遅延が低く、スレッドに順序がない場合は、sleep()またはwait()メソッドを呼び出す代わりに、キュー内の新しいメッセージをループ検出することができます.唯一のメリットは、数マイクロ秒や数ナノ秒などの短い時間を待つことです.LMAX分散フレームワークは、BusySpinWaitStrategyクラスがこの概念に基づいて実装され、busy spinサイクルEventProcessorsを使用してバリアを待つ高性能スレッド間通信のライブラリです.
9、Javaでスレッドdumpファイルをどのように取得しますか?
Linuxでは、キル-3 PIDを命令することで(JavaプロセスのプロセスID)Javaアプリケーションのdumpファイルを取得します.WindowsではCtrl+Breakを押して取得できます.これにより、JVMはスレッドのdumpファイルを標準出力またはエラーファイルに印刷し、コンソールまたはログファイルに印刷することができます.特定の場所はアプリケーションの構成に依存します.Tomcatを使用する場合.
10、Swingはスレッドが安全ですか?
いいえ、Swingはスレッドが安全ではありません.JTable、JList、JPanelなどのSwingコンポーネントは、どのスレッドでも更新できません.実際には、GUIまたはAWTスレッドでしか更新できません.そのため、Swingは、他のスレッドのGUI更新要求を取得するためにinvokeAndWait()およびinvokeLater()メソッドを提供する.これらのメソッドは、更新要求をAWTのスレッドキューに入れ、ずっと待つこともできるし、非同期更新で直接結果を返すこともできる.また、参考答案でより詳細な内容を表示したり勉強したりすることもできます.
11、スレッドローカル変数とは?
スレッドローカル変数は、スレッド内部に限られた変数であり、スレッド自体の所有であり、複数のスレッド間で共有されない.Javaはスレッドローカル変数をサポートするThreadLocalクラスを提供し、スレッドセキュリティを実現する方法です.ただし、Webサーバなどの管理環境でスレッドローカル変数を使用する場合は、特に注意してください.この場合、ワークスレッドのライフサイクルは、アプリケーション変数のライフサイクルよりも長くなります.任意のスレッドローカル変数が作業完了後に解放されないと、Javaアプリケーションではメモリが漏洩するリスクがあります.
12、wait-notifyでコードを書いて生産者-消費者の問題を解決しますか?
同期ブロックでwait()メソッドとnotify()メソッドを呼び出すことを覚えておけば、ブロックされた場合、待機条件をループでテストします.
13、Javaで1つのスレッドの安全な単例のモード(Singleton)を書きますか?
一歩一歩、スレッドが安全なJava単一クラスを作成します.スレッドが安全だと言うと、初期化がマルチスレッド環境であっても、単一のインスタンスが保証されることを意味します.Javaでは、列挙を単一クラスとして使用するのが最も簡単な方法で、スレッドセキュリティ単一モードを作成する方法です.
14、Javaにおけるsleepメソッドとwaitメソッドの違い?
両方とも現在実行中のスレッドを一時停止するために使用されますが、sleep()は実際には一時停止にすぎません.ロックは解放されないため、wait()は条件待機を意味します.これは、他の待機スレッドが条件を満たすときにロックを取得できる理由です.
15、可変オブジェクト(immutable object)とは?Javaで可変オブジェクトを作成するにはどうすればいいですか?
可変オブジェクトとは、オブジェクトが作成されると、ステータスが変更されないことを意味します.変更すると、String、Integer、その他のパッケージクラスなどの新しいオブジェクトが作成されます.詳細は答えを参照してください.Javaで可変クラスを作成するには、一歩一歩指導します.
16、可変オブジェクトを含む可変オブジェクトを作成できますか?
はい、可変オブジェクトを含む可変オブジェクトを作成できます.可変オブジェクトの参照を共有しないでください.変更が必要な場合は、元のオブジェクトのコピーを返します.最も一般的な例は、オブジェクトに日付オブジェクトが含まれている参照です.データ型とJavaベースの面接問題
17、Javaではどのようなデータ型を使って価格を表すべきですか?
メモリやパフォーマンスに特に関心がない場合は、BigDecimalを使用します.そうでない場合は、あらかじめ定義された精度のdoubleタイプを使用します.
18、byteをStringに変換するにはどうすればいいですか?
Stringを使用してbyte[]パラメータを受信するコンストラクタを使用して変換することができます.注意しなければならないのは、正しい符号化を使用することです.そうしないと、プラットフォームのデフォルト符号化が使用されます.この符号化は、元の符号化と同じか、異なる可能性があります.
19、Javaでbytes[]をlongタイプに変換するにはどうすればいいですか?
bytes[]からデジタルタイプへの変換はよく使われるコードであり、解決策も一つではない.
JAvaコード実装は、既存のクラスを借りたくない場合は、次のように完全に自分で実装できます.
/**
     *        long
* input null, offset 8 *
@param input * @param offset * @param littleEndian * @return */public static long longFrom8Bytes(byte[] input, int offset, Boolean littleEndian){ long value=0; // long 8 for (int count=0;count<8;++count){ int shift=(littleEndian?count:(7-count))<<3; value |=((long)0xff<< shift) & ((long)input[offset+count] << shift); } return value;}

Javaを借りる.nio.ByteBuffer実装
java.nio.ByteBuffer自体にgetLong,getInt,getFloat....メソッドは、byte[]をByteBufferに変換するだけで、javadocを参照してすべてのprimitiveタイプのデータ読み出しを実現できます.
/**
     *    {@link java.nio.ByteBuffer}  byte[] long
     * @param input
     * @param offset
     * @param littleEndian           
     * @return
     */public static long bytesTolong(byte[] input, int offset, Boolean littleEndian) {
    //  byte[]     ByteBuffer
    ByteBuffer buffer = ByteBuffer.wrap(input,offset,8);
    if(littleEndian){
        // ByteBuffer.order(ByteOrder)        ,      (BIG_ENDIAN/LITTLE_ENDIAN)
        // ByteBuffer      (BIG_ENDIAN)  
        buffer.order(ByteOrder.LITTLE_ENDIAN);
    }
    return buffer.getlong();}

Javaを借りる.io.DataInputStream実装
java.io.DataInputStreamもreadLong,readLong,readLong....を提供している.メソッドは、byte[]をDataInputStreamに変換するだけで、javadocを参照してすべてのprimitiveタイプのデータ読み出しを実現できます.
20、intをbyteタイプの変数に強制的に変換できますか?この値がbyteタイプの範囲より大きい場合、どのような現象が発生しますか?
はい、強制変換はできますが、Javaではintが32ビットでbyteが8ビットなので、強制変換ではintタイプの高さ24ビットが捨てられ、byteタイプの範囲は-128から127です.