JavaRush /Java Blog /Random-TW /喝咖啡休息#112。如何在 Java 中宣告、初始化和迭代數組。如何在不使用 Thread.stop() 的情況下...

喝咖啡休息#112。如何在 Java 中宣告、初始化和迭代數組。如何在不使用 Thread.stop() 的情況下停止 Java 執行緒?

在 Random-TW 群組發布

如何在 Java 中宣告、初始化和迭代數組

資料來源:FreeCodeCamp 在本文中,我們將討論 Java 中的陣列。我們將透過一些範例來幫助您了解陣列是什麼、如何聲明它以及如何在 Java 程式碼中使用它。 喝咖啡休息#112。 如何在 Java 中宣告、初始化和迭代數組。 如何在不使用 Thread.stop() 的情況下停止 Java 執行緒? - 1

什麼是數組?

在Java中,我們使用陣列在單一變數中儲存相同資料類型的多個值。也可以將其視為相同資料類型的值的集合。這意味著,例如,如果您要在數組中儲存字串,那麼數組中的所有值都必須是字串。

如何在Java中聲明數組

我們使用方括號[]來宣告一個陣列。像那樣:
String[] names;
這裡我們宣告了一個名為名稱的變量,它將保存一個字串數組。如果我們需要聲明一個整數(integers)變量,那麼我們會這樣做:
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
現在我們知道如何存取每個元素,讓我們更改第三個元素的值。
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 執行緒?

來源:4compressive如果您正在閱讀本文,那麼您可能想知道為什麼,最重要的是,如果您不能僅依賴Thread#stop() 方法(該方法自 Java 1.2 以來已被棄用) ,如何停止線程? 喝咖啡休息#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#interrupt而不是Thread#stop還不夠。執行緒的安全終止只能透過使用共享執行緒中斷來實現,這意味著在執行緒內我們需要處理中斷訊號,中斷訊號有兩種類型:
  • 布林中斷標誌

  • 中斷異常

可中斷標誌處理

在線程內部時,我們可以透過呼叫以下方法之一來檢查它是否已中斷:
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()不是一回事。第一個只是讀取中斷標誌,另一個隨後將其重置。

  • 處理中斷訊號沒有通用的方法——“這取決於具體情況。”

留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION