JavaRush /จาวาบล็อก /Random-TH /คอฟฟี่เบรค #112. วิธีการประกาศ เริ่มต้น และวนซ้ำอาร์เรย์ใ...

คอฟฟี่เบรค #112. วิธีการประกาศ เริ่มต้น และวนซ้ำอาร์เรย์ใน Java จะหยุดเธรด Java โดยไม่ใช้ Thread.stop() ได้อย่างไร

เผยแพร่ในกลุ่ม

วิธีการประกาศ เริ่มต้น และวนซ้ำอาร์เรย์ใน Java

ที่มา: FreeCodeCamp ในบทความนี้ เราจะพูดถึงอาร์เรย์ใน Java เราจะดูตัวอย่างเล็กๆ น้อยๆ เพื่อช่วยให้คุณเข้าใจว่าอาร์เรย์คืออะไร วิธีประกาศอาร์เรย์ และวิธีใช้ในโค้ด Java คอฟฟี่เบรค #112.  วิธีการประกาศ เริ่มต้น และวนซ้ำอาร์เรย์ใน Java  จะหยุดเธรด Java โดยไม่ใช้ Thread.stop() ได้อย่างไร  - 1

อาร์เรย์คืออะไร?

ใน Java เราใช้อาร์เรย์เพื่อเก็บค่าหลายค่าของประเภทข้อมูลเดียวกันไว้ในตัวแปรตัวเดียว นอกจากนี้ยังถือได้ว่าเป็นชุดของค่าประเภทข้อมูลเดียวกัน ซึ่งหมายความว่าหากคุณจะจัดเก็บสตริงในอาร์เรย์ของคุณ ค่าทั้งหมดในอาร์เรย์ของคุณก็จะต้องเป็นสตริง

วิธีการประกาศอาร์เรย์ใน Java

เราใช้ วงเล็บ เหลี่ยม [ ]เพื่อประกาศอาร์เรย์ เช่นนั้น:
String[] 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
ตอนนี้เรารู้วิธีเข้าถึงแต่ละองค์ประกอบแล้ว เรามาเปลี่ยนค่าขององค์ประกอบที่สามกันดีกว่า
String[] names = {"John", "Jade", "Love", "Allen"};
names[2] = "Victor";

System.out.println(names[2]);
// Victor
นอกจากนี้เรายังสามารถตรวจสอบความ ยาว ของอาร์เรย์โดยใช้ คุณสมบัติ ความยาว นี่คือตัวอย่าง:
String[] names = {"John", "Jade", "Love", "Allen"};
System.out.println(names.length);
// 4

วิธีวนซ้ำผ่านอาร์เรย์ใน Java

เราสามารถใช้for loop เพื่อวนซ้ำองค์ประกอบของอาร์เรย์ ได้
String[] names = {"John", "Jade", "Love", "Allen"};
for (int i = 0; i < names.length; i++) {
  System.out.println(names[i]);
}

// John
// Jade
// Love
// Allen
การวนซ้ำด้านบนจะพิมพ์องค์ประกอบของอาร์เรย์ของเรา เราใช้ คุณสมบัติ ความยาวเพื่อระบุจำนวนครั้งที่ควรรันลูป

บทสรุป

ในบทความนี้ เราได้เรียนรู้วิธีประกาศและเริ่มต้นอาร์เรย์ในโค้ด Java เรายังได้เห็นวิธีเข้าถึงแต่ละองค์ประกอบของอาร์เรย์และวิธีวนซ้ำองค์ประกอบเหล่านั้น ขอให้มีความสุขในการเขียนโค้ด!

จะหยุดเธรด Java โดยไม่ใช้ Thread.stop() ได้อย่างไร

ที่มา: 4comprehension หากคุณกำลังอ่านข้อความนี้ คุณอาจสงสัยว่าทำไม และที่สำคัญที่สุดคือ จะหยุดเธรดได้อย่างไร หากคุณไม่สามารถพึ่งพาเมธอด Thread#stop() ซึ่งเลิกใช้แล้วตั้งแต่ Java 1.2 ? คอฟฟี่เบรค #112.  วิธีการประกาศ เริ่มต้น และวนซ้ำอาร์เรย์ใน Java  จะหยุดเธรด Java โดยไม่ใช้ Thread.stop() ได้อย่างไร  - 2คำตอบสั้นๆ ก็คือ คุณควรใช้การขัดจังหวะ เนื่องจากThread#stopไม่ปลอดภัย แต่ถ้าคุณต้องการทำความเข้าใจว่าทำไมInterruptedException และสิ่งที่น่ารำคาญนั้นมีไว้เพื่ออะไร โปรดอ่านต่อ

ปัญหากับ Thread#stop()

ไม่ว่ามันจะฟังดูเป็นธรรมชาติแค่ไหน การขัดจังหวะเธรดที่กำลังทำงานอยู่ การสตาร์ทและการหยุดเป็นสองกรณีที่แตกต่างกันโดยสิ้นเชิง ทำไม เมื่อเราเริ่มเธรดใหม่ เรากำลังเริ่มต้นจากศูนย์ซึ่งเป็นสถานะที่กำหนดไว้อย่างดี แต่เมื่อเราพยายามหยุดเธรดที่มีอยู่ อาจเกิดขึ้นในระหว่างการดำเนินการที่ไม่สามารถขัดจังหวะได้ทันที ลองนึกภาพเธรดที่ทำการเปลี่ยนแปลงโครงสร้างข้อมูลที่ปลอดภัยของเธรด ในขณะที่มันอยู่ตรงกลางของส่วนวิกฤติ... จากนั้นเธรดก็หายไปอย่างน่าอัศจรรย์ - การล็อคจะถูกปลดล็อค และตอนนี้เธรดอื่นสามารถสังเกตโครงสร้างข้อมูลที่เหลืออยู่ในสถานะที่ไม่สอดคล้องกัน พิจารณาตัวอย่างต่อไปนี้ของตัวนับ thread-safe ที่มีสถานะภายในบางอย่าง:
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;
    }
}
อย่างที่คุณเห็น เมธอด getAndIncreation()จะเพิ่มตัวนับและเปลี่ยนค่า สถานะ สกปรก การล็อคช่วยให้มั่นใจได้ว่าทุก ครั้งที่เธรดเข้าสู่getAndIncreation()แฟล็กสกปรกจะถูกตั้งค่าเป็น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 instance แม้จะมีการใช้งานอย่างถูกต้อง แต่ก็ได้รับความเสียหายอย่างถาวรเนื่องจากการหยุดเธรดอย่างกะทันหัน จะแก้ไขได้อย่างไร?

การหยุดชะงักของเธรดแบบร่วมมือ

แทนที่จะหยุดเธรด เราควรอาศัยการหยุดชะงักของเธรดแบบร่วมมือ พูดง่ายๆ ก็คือ เราต้องขอให้เธรดหยุดตัวเองในช่วงเวลาที่เหมาะสมโดยใช้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

จะเกิดอะไรขึ้นถ้าเราพยายามขัดจังหวะเธรดที่รออยู่? โดยปกติแล้ว เราไม่สามารถ คำนึงถึงแฟล็ก การขัดจังหวะได้เนื่องจากเธรดกำลังยุ่งอยู่กับการดำเนินการบล็อก นั่นเป็นสาเหตุที่ InterruptedExceptionมีอยู่ นี่ไม่ใช่ข้อยกเว้นมาตรฐาน แต่เป็นสัญญาณขัดจังหวะรูปแบบอื่นที่มีอยู่เพื่อจัดการกับการขัดจังหวะการบล็อกเท่านั้น! เช่นเดียวกับThread#interruptedมันจะรีเซ็ตการตั้ง ค่าสถานะ การหยุดชะงัก ลองเปลี่ยนตัวอย่างด้านบนอีกครั้งและแนะนำการหยุดชั่วคราวก่อนการเพิ่มแต่ละครั้ง ตอนนี้เราต้องจัดการกับInterruptedExceptionที่ถูกโยนโดยThread#sleep :
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