วิธีการประกาศ เริ่มต้น และวนซ้ำอาร์เรย์ใน Java
ที่มา: FreeCodeCamp ในบทความนี้ เราจะพูดถึงอาร์เรย์ใน Java เราจะดูตัวอย่างเล็กๆ น้อยๆ เพื่อช่วยให้คุณเข้าใจว่าอาร์เรย์คืออะไร วิธีประกาศอาร์เรย์ และวิธีใช้ในโค้ด Java
อาร์เรย์คืออะไร?
ใน 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 ?
ปัญหากับ 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()ไม่เหมือนกัน อันแรกเพียงอ่าน แฟล็ก การหยุดชะงักและอีกอันจะรีเซ็ตในภายหลัง
-
ไม่มีวิธีสากลในการจัดการกับสัญญาณขัดจังหวะ - "ขึ้นอยู่กับสถานการณ์"
GO TO FULL VERSION