มีเงื่อนไขใดบ้างที่ในที่สุดอาจไม่ทำงานใน java? ขอบคุณ
มีเงื่อนไขใดบ้างที่ในที่สุดอาจไม่ทำงานใน java? ขอบคุณ
คำตอบ:
จากบทแนะนำ Sun
หมายเหตุ: หาก JVM ออกในขณะที่กำลังเรียกใช้รหัส try หรือ catch การบล็อกในที่สุดอาจไม่ดำเนินการ ในทำนองเดียวกันหากเธรดที่เรียกใช้โค้ด try หรือ catch ถูกขัดจังหวะหรือถูกฆ่าสุดท้ายการบล็อกอาจไม่ดำเนินการแม้ว่าแอปพลิเคชันโดยรวมจะยังคงดำเนินต่อไป
ฉันไม่รู้วิธีอื่นใดที่สุดท้ายบล็อกจะไม่ดำเนินการ ...
System.exitปิดเครื่องเสมือน
ยุติ Java Virtual Machine ที่กำลังรันอยู่ อาร์กิวเมนต์ทำหน้าที่เป็นรหัสสถานะ ตามแบบแผนรหัสสถานะที่ไม่ใช่ศูนย์แสดงถึงการยุติที่ผิดปกติ
วิธีการนี้เรียกว่าวิธีการในชั้นเรียน
exit
Runtime
วิธีนี้จะไม่คืนค่าตามปกติ
try {
System.out.println("hello");
System.exit(0);
}
finally {
System.out.println("bye");
} // try-finally
"ลาก่อน" ไม่ได้พิมพ์ออกมาในโค้ดด้านบน
เพียงเพื่อขยายความในสิ่งที่คนอื่นพูดอะไรก็ตามที่ไม่ก่อให้เกิดบางอย่างเช่นการออกจาก JVM จะทำให้เกิดการปิดกั้นในที่สุด ดังนั้นวิธีการต่อไปนี้:
public static int Stupid() {
try {
return 0;
}
finally {
return 1;
}
}
จะรวบรวมและส่งคืน 1 อย่างแปลกประหลาด
ที่เกี่ยวข้องกับ System.exit นอกจากนี้ยังมีความล้มเหลวบางประเภทที่การบล็อกในที่สุดอาจไม่ทำงาน หาก JVM หมดหน่วยความจำทั้งหมดก็อาจจะออกโดยไม่ต้องจับหรือเกิดขึ้นในที่สุด
โดยเฉพาะอย่างยิ่งฉันจำโครงการที่เราพยายามใช้อย่างโง่เขลา
catch (OutOfMemoryError oome) {
// do stuff
}
สิ่งนี้ไม่ได้ผลเนื่องจาก JVM ไม่มีหน่วยความจำเหลือสำหรับการเรียกใช้บล็อก catch
try { for (;;); } finally { System.err.println("?"); }
ในกรณีนี้สุดท้ายจะไม่ดำเนินการ (เว้นแต่Thread.stop
จะเรียกว่าเลิกใช้แล้วหรือเทียบเท่าพูดผ่านอินเทอร์เฟซเครื่องมือ)
throw
แล้วfinally
บล็อกจะดำเนินการตามที่คาดไว้ try { throw new ThreadDeath(); } finally { System.err.println("?"); }
บทแนะนำของ The Sun ถูกยกมาอย่างไม่ถูกต้องในหัวข้อนี้
หมายเหตุ: หาก JVM ออกในขณะที่กำลังเรียกใช้รหัส try หรือ catch สุดท้ายบล็อกจะไม่ดำเนินการ ในทำนองเดียวกันหากเธรดที่เรียกใช้โค้ด try หรือ catch ถูกขัดจังหวะหรือถูกฆ่าสุดท้ายการบล็อกจะไม่ทำงานแม้ว่าแอปพลิเคชันโดยรวมจะยังคงดำเนินต่อไป
หากคุณดูบทแนะนำเกี่ยวกับซันอย่างใกล้ชิดสำหรับการบล็อกในที่สุดมันไม่ได้บอกว่า "จะไม่ดำเนินการ" แต่ "อาจไม่ดำเนินการ" นี่คือคำอธิบายที่ถูกต้อง
หมายเหตุ: หาก JVM ออกในขณะที่กำลังเรียกใช้รหัส try หรือ catch การบล็อกในที่สุดอาจไม่ดำเนินการ ในทำนองเดียวกันหากเธรดที่เรียกใช้โค้ด try หรือ catch ถูกขัดจังหวะหรือถูกฆ่าสุดท้ายการบล็อกอาจไม่ดำเนินการแม้ว่าแอปพลิเคชันโดยรวมจะยังคงดำเนินต่อไป
เหตุผลที่ชัดเจนสำหรับพฤติกรรมนี้คือการเรียกใช้ system.exit () ถูกประมวลผลในเธรดระบบรันไทม์ซึ่งอาจใช้เวลาในการปิด jvm ในขณะที่ตัวกำหนดตารางเวลาเธรดสามารถขอให้ดำเนินการได้ในที่สุด ในที่สุดก็ถูกออกแบบมาให้ดำเนินการเสมอ แต่ถ้าคุณปิด jvm มันอาจเกิดขึ้นที่ jvm ปิดตัวลงก่อนที่จะถูกเรียกใช้งานในที่สุด
นอกจากนี้หากการหยุดชะงัก / การล็อกเกิดขึ้นภายในtry
บล็อก
นี่คือรหัสที่แสดงให้เห็น:
public class DeadLocker {
private static class SampleRunnable implements Runnable {
private String threadId;
private Object lock1;
private Object lock2;
public SampleRunnable(String threadId, Object lock1, Object lock2) {
super();
this.threadId = threadId;
this.lock1 = lock1;
this.lock2 = lock2;
}
@Override
public void run() {
try {
synchronized (lock1) {
System.out.println(threadId + " inside lock1");
Thread.sleep(1000);
synchronized (lock2) {
System.out.println(threadId + " inside lock2");
}
}
} catch (Exception e) {
} finally {
System.out.println("finally");
}
}
}
public static void main(String[] args) throws Exception {
Object ob1 = new Object();
Object ob2 = new Object();
Thread t1 = new Thread(new SampleRunnable("t1", ob1, ob2));
Thread t2 = new Thread(new SampleRunnable("t2", ob2, ob1));
t1.start();
t2.start();
}
}
รหัสนี้สร้างผลลัพธ์ต่อไปนี้:
t1 inside lock1
t2 inside lock1
และ "ในที่สุด" จะไม่ได้รับการพิมพ์
หาก JVM ออกในขณะที่กำลังดำเนินการ try หรือ catch โค้ดสุดท้ายบล็อกอาจไม่ทำงาน (ที่มา )
Normal Shutdown - เกิดขึ้นเมื่อเธรดที่ไม่ใช่ daemon ตัวสุดท้ายออกจากหรือเมื่อ Runtime.exit () ( ต้นทาง )
เมื่อเธรดออก JVM จะดำเนินการจัดเก็บเธรดที่รันอยู่และหากเธรดเดียวที่เหลือเป็นเธรด daemon เธรดจะเริ่มการปิดระบบตามลำดับ เมื่อ JVM หยุดทำงานเธรด daemon ที่เหลือจะถูกละทิ้งในที่สุดบล็อกจะไม่ถูกดำเนินการสแต็กจะไม่คลาย JVM เพียงแค่ออก เธรด Daemon ควรใช้กิจกรรมการประมวลผลเพียงเล็กน้อยสามารถละทิ้งได้อย่างปลอดภัยเมื่อใดก็ได้โดยไม่ต้องล้างข้อมูล โดยเฉพาะอย่างยิ่งการใช้เธรด daemon สำหรับงานที่อาจดำเนินการ I / O ประเภทใดก็ได้เป็นอันตราย เธรด Daemon ถูกบันทึกไว้อย่างดีที่สุดสำหรับงาน "การดูแลทำความสะอาด" เช่นเธรดพื้นหลังที่ลบรายการที่หมดอายุออกจากแคชในหน่วยความจำเป็นระยะ (ที่มา )
เธรดที่ไม่ใช่ daemon ตัวสุดท้ายออกจากตัวอย่าง:
public class TestDaemon {
private static Runnable runnable = new Runnable() {
@Override
public void run() {
try {
while (true) {
System.out.println("Is alive");
Thread.sleep(10);
// throw new RuntimeException();
}
} catch (Throwable t) {
t.printStackTrace();
} finally {
System.out.println("This will never be executed.");
}
}
};
public static void main(String[] args) throws InterruptedException {
Thread daemon = new Thread(runnable);
daemon.setDaemon(true);
daemon.start();
Thread.sleep(100);
// daemon.stop();
System.out.println("Last non-daemon thread exits.");
}
}
เอาท์พุท:
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Is alive
Last non-daemon thread exits.
Is alive
Is alive
Is alive
Is alive
Is alive
ในกรณีต่อไปนี้สุดท้ายบล็อกจะไม่ถูกดำเนินการ: -
System.exit(0)
ถูกเรียกใช้จากtry
บล็อก try
บล็อก ของคุณนอกจากนี้ยังอาจมีกรณีอื่น ๆ อีกด้วยซึ่งสุดท้ายแล้วการบล็อกจะไม่ถูกดำเนินการ
มีสองวิธีในการหยุดการทำงานของโค้ดในที่สุด:
1. ใช้ System.exit ();
2. หากการควบคุมการดำเนินการไม่ถึงพยายามบล็อก
ดู:
public class Main
{
public static void main (String[]args)
{
if(true){
System.out.println("will exceute");
}else{
try{
System.out.println("result = "+5/0);
}catch(ArithmeticException e){
System.out.println("will not exceute");
}finally{
System.out.println("will not exceute");
}
}
}
}
ฉันเจอกรณีที่เฉพาะเจาะจงมากของการบล็อกในที่สุดที่ไม่ได้ดำเนินการที่เกี่ยวข้องกับกรอบการเล่นโดยเฉพาะ
ฉันประหลาดใจที่พบว่าในที่สุดบล็อกในโค้ดแอ็คชันคอนโทรลเลอร์นี้จะถูกเรียกหลังจาก Exception เท่านั้น แต่ไม่เคยเมื่อการโทรสำเร็จจริง
try {
InputStream is = getInputStreamMethod();
renderBinary(is, "out.zip");
catch (Exception e) {
e.printStackTrace();
} finally {
cleanUp();
}
บางทีเธรดอาจถูกยกเลิกหรือมีบางอย่างเมื่อเรียกใช้ renderBinary () ฉันสงสัยว่าสิ่งเดียวกันนี้จะเกิดขึ้นกับการเรียกใช้ render () อื่น ๆ แต่ฉันไม่ได้ตรวจสอบ
ฉันแก้ไขปัญหาโดยการย้าย renderBinary () ไปที่หลังจากลอง / จับ การตรวจสอบเพิ่มเติมพบว่า play มีคำอธิบายประกอบ @Finally เพื่อสร้างวิธีการที่ได้รับการดำเนินการหลังจากดำเนินการกับคอนโทรลเลอร์ ข้อแม้ที่นี่คือสิ่งนี้จะถูกเรียกหลังจากการดำเนินการใด ๆ ในคอนโทรลเลอร์ดังนั้นจึงอาจไม่ใช่ทางเลือกที่ดีเสมอไป
//If ArithmeticException Occur Inner finally would not be executed
class Temp
{
public static void main(String[] s)
{
try
{
int x = 10/s.length;
System.out.println(x);
try
{
int z[] = new int[s.length];
z[10] = 1000;
}catch(ArrayIndexOutOfBoundsException e)
{
System.out.println(e);
}
finally
{
System.out.println("Inner finally");
}
}
catch(ArithmeticException e)
{
System.out.println(e);
}
finally
{
System.out.println("Outer Finally");
}
System.out.println("Remaining Code");
}
}