JavaRush /Java Blog /Random-JA /コーヒーブレイク#112。Java で配列を宣言、初期化し、反復処理する方法。Thread.stop() を使用せ...

コーヒーブレイク#112。Java で配列を宣言、初期化し、反復処理する方法。Thread.stop() を使用せずに Java スレッドを停止するにはどうすればよいですか?

Random-JA グループに公開済み

Java で配列を宣言、初期化し、反復処理する方法

出典: FreeCodeCamp この記事では、Java の配列について説明します。配列とは何か、配列を宣言する方法、および Java コードで配列を使用する方法を理解するのに役立ついくつかの例を見ていきます。 コーヒーブレイク#112。 Java で配列を宣言、初期化し、反復処理する方法。 Thread.stop() を使用せずに Java スレッドを停止するにはどうすればよいですか?  - 1

配列とは何ですか?

Java では、配列を使用して、同じデータ型の複数の値を 1 つの変数に格納します。同じデータ型の値のコレクションと考えることもできます。これは、たとえば配列に文字列を格納する場合、配列内のすべての値が文字列である必要があることを意味します。

Javaで配列を宣言する方法

配列を宣言するには角括弧[]を使用します。そのように:
String[] names;
ここでは、文字列の配列を保持するnames という変数を宣言しました。整数(整数)の変数を宣言する必要がある場合は、次のようにします。
int[] myIntegers;
したがって、配列を作成するには、配列に格納するデータのタイプを指定し、その後に角かっこ、次に配列の名前を指定します。

Javaで配列を初期化する方法

配列を初期化するとは、配列に値を割り当てることを意味します。前のセクションで宣言した配列を初期化しましょう。
String[] names = {"John", "Jade", "Love", "Allen"};
int[] myIntegers = {10, 11, 12};
同じデータ型の値を渡し、各値をカンマで区切って配列を初期化しました。配列内の要素/値にアクセスしたい場合は、配列内のそれらのインデックス番号にアクセスします。最初の要素のインデックスは 0 です。例を次に示します。
String[] names = {"John", "Jade", "Love", "Allen"};

System.out.println(names[0]);
// John

System.out.println(names[1]);
// Jade

System.out.println(names[2]);
// Love

System.out.println(names[3]);
// Allen
各要素にアクセスする方法がわかったので、3 番目の要素の値を変更しましょう。
String[] names = {"John", "Jade", "Love", "Allen"};
names[2] = "Victor";

System.out.println(names[2]);
// Victor
lengthプロパティ を使用して配列の長さをチェックすることもできます。以下に例を示します。
String[] names = {"John", "Jade", "Love", "Allen"};
System.out.println(names.length);
// 4

Java で配列を反復処理する方法

forループを使用して、配列の要素を反復処理できます。
String[] names = {"John", "Jade", "Love", "Allen"};
for (int i = 0; i < names.length; i++) {
  System.out.println(names[i]);
}

// John
// Jade
// Love
// Allen
上記のループは配列の要素を出力します。lengthプロパティを使用して、ループを実行する回数を指定しました。

結論

この記事では、Java コードで配列を宣言して初期化する方法を学びました。また、配列の各要素にアクセスする方法と、それらの要素をループする方法についても説明しました。コーディングを楽しんでください!

Thread.stop() を使用せずに Java スレッドを停止するにはどうすればよいですか?

出典: 4comprehensionこれを読んでいるということは、 Java 1.2 以降非推奨になったThread#stop() メソッドに頼ることができないのに、なぜスレッドを停止するのか、そして最も重要なことに、どのようにスレッドを停止するのか疑問に思っていることでしょう。 ? コーヒーブレイク#112。 Java で配列を宣言、初期化し、反復処理する方法。 Thread.stop() を使用せずに Java スレッドを停止するにはどうすればよいですか?  - 2簡単に言うと、Thread#stop は安全ではないため、割り込みを使用する必要があります。ただし、その厄介なInterruptedExceptionがなぜ、どのように、何のために発生するのかを理解したい場合は、読み続けてください。

Thread#stop() の問題

どれほど直感的に聞こえるかもしれませんが、すでに実行中のスレッドを中断することと、開始​​と停止はまったく異なるケースです。なぜ?新しいスレッドを開始するときは、最初から開始することになり、これは明確に定義された状態ですが、既存のスレッドを停止しようとすると、すぐに中断できない操作の途中で停止する可能性があります。スレッドがスレッドセーフなデータ構造に変更を加えていると想像してください。クリティカル セクションの途中にある間...その後、スレッドは魔法のように消えます。ロックが解放され、別のスレッドが不整合な状態に残されたデータ構造を観察できるようになります。内部状態を含むスレッドセーフ カウンターの次の例を考えてみましょう。
class ThreadSafeCounter {

    private volatile int counter = 0;
    private volatile boolean dirty = false;

    public synchronized int incrementAndGet() {
        if (dirty) {
            throw new IllegalStateException("this should never happen");
        }
        dirty = true;
        // ...
        Thread.sleep(5000); // boilerplate not included
        // ...
        counter = counter + 1;
        dirty = false;
        return counter;
    }
}
ご覧のとおり、getAndIncrement()メソッドはカウンターをインクリメントし、ダーティフラグを変更します。ロックにより、スレッドがgetAndIncrement()に入るたびに、ダーティフラグがfalseに設定されます。次に、スレッドを作成し、突然停止してみましょう。
var threadSafeCounter = new ThreadSafeCounter();

var t1 = new Thread(() -> {
    while (true) {
        threadSafeCounter.incrementAndGet();
    }
});

t1.start();
Thread.sleep(500);
t1.stop();

threadSafeCounter.incrementAndGet();

// Exception in thread "main" java.lang.IllegalStateException: this should never happen
threadSafeCounterインスタンスは、正しく実装されているにもかかわらず、スレッドが突然停止されたため、永久に破損していますそれを修正するにはどうすればよいですか?

協調スレッド中断

スレッドを停止する代わりに、協調的なスレッドの中断に頼るべきです。簡単に言えば、 Thread#interruptを使用して、適切なタイミングでスレッド自体を停止するように要求する必要があります。ただし、Thread#stopの代わりにThread#interrupt を呼び出すだけでは十分ではありません。スレッドを安全に終了するには、共有スレッド割り込みを使用する必要があります。つまり、スレッド内で次の 2 種類の割り込み信号を処理する必要があります。
  • ブール値の中断フラグ

  • 中断された例外

割り込み可能なフラグの処理

スレッド内で、次のいずれかのメソッドを呼び出すことで、スレッドが中断されたかどうかを確認できます。
Thread.currentThread().isInterrupted(); // reads the interrupted flag
Thread.interrupted(); // reads and resets the interrupted flag
割り込みを処理する普遍的な方法はないため、コンテキストに適したアクションを適用する必要があります。前のセクションの例では、スレッドは無限ループでカウンターをインクリメントします。すぐに停止する代わりに、スレッドが上昇作業を完了するのを待ってからループを終了することもできます。
var threadSafeCounter = new ThreadSafeCounter();

var t1 = new Thread(() -> {
    while (!Thread.interrupted()) {
        threadSafeCounter.incrementAndGet();
    }
});

t1.start();
Thread.sleep(500);
t1.interrupt();

threadSafeCounter.incrementAndGet();
これで、スレッドは混乱を引き起こすことなく適切なタイミングで安全に終了します。

中断例外の処理

待機中のスレッドを中断しようとするとどうなるでしょうか? 当然のことながら、スレッドはブロック操作でビジー状態であるため、割り込みフラグを考慮することはできません。そのため、 InterruptedException が存在します。これは標準の例外ではなく、ブロッキング割り込みを処理するためだけに存在する別の形式の割り込み信号です。Thread#interruptedと同様に、割り込みフラグをリセットします。上記の例を再度変更して、各増分の前に一時停止を導入してみましょう。ここで、 Thread#sleepによってスローされたInterruptedExceptionを処理する必要があります。
var threadSafeCounter = new ThreadSafeCounter();

var t1 = new Thread(() -> {
    while (!Thread.interrupted()) {
        threadSafeCounter.incrementAndGet();
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            break;
        }
    }
});

t1.start();
Thread.sleep(500);
t1.interrupt();

assertThat(threadSafeCounter.incrementAndGet()).isGreaterThan(0);
私たちの場合は、単にループを終了するだけで十分でした。しかし、特定のメソッドが割り込みの処理を担当する必要がないと思われる場合はどうすればよいでしょうか? メソッドのシグネチャを変更できない場合はどうなるでしょうか? この場合、中断フラグを復元するか、例外を再パッケージ化するか、あるいはその両方を行う必要があります。次に例を示します。
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
}
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    Thread.currentThread().interrupt();
    throw new RuntimeException(e);
}

結論:

  • Thread#stop は理由もなく非推奨になっているわけではありません。実際には非常に安全ではありません。

  • スレッドは割り込み、つまりスレッド自体によって解釈される信号によって停止されます。

  • InterruptedException は通常の例外ではありません。これは、スレッドが中断されたことを通知する Java の組み込みの方法です。

  • Thread.currentThread().isInterrupted()Thread.interrupted() は同じものではありません。最初のものは単純に中断フラグを読み取り、もう 1 つはその後それをリセットします。

  • 割り込み信号を処理する普遍的な方法はありません。「状況に応じて異なります」。

コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION