Có điều kiện nào mà cuối cùng có thể không chạy trong java không? Cảm ơn.
Có điều kiện nào mà cuối cùng có thể không chạy trong java không? Cảm ơn.
Câu trả lời:
Lưu ý: Nếu JVM thoát ra trong khi mã thử hoặc bắt đang được thực thi, thì khối cuối cùng có thể không thực thi. Tương tự như vậy, nếu chuỗi thực thi mã try hoặc catch bị gián đoạn hoặc bị giết, khối cuối cùng có thể không thực thi mặc dù toàn bộ ứng dụng vẫn tiếp tục.
Tôi không biết có cách nào khác mà khối cuối cùng sẽ không thực thi ...
System.exit tắt Máy ảo.
Chấm dứt Máy ảo Java hiện đang chạy. Đối số đóng vai trò như một mã trạng thái; theo quy ước, mã trạng thái khác không cho biết kết thúc bất thường.
Phương thức này gọi
exit
phương thức trong lớpRuntime
. Phương thức này không bao giờ trả về bình thường.
try {
System.out.println("hello");
System.exit(0);
}
finally {
System.out.println("bye");
} // try-finally
"bye" không in ra trong mã trên.
Chỉ để mở rộng những gì những người khác đã nói, bất cứ điều gì không gây ra điều gì đó giống như việc thoát JVM sẽ phải chịu khối cuối cùng. Vì vậy, phương pháp sau:
public static int Stupid() {
try {
return 0;
}
finally {
return 1;
}
}
kỳ lạ sẽ cả biên dịch và trả về 1.
Liên quan đến System.exit, cũng có một số loại lỗi nghiêm trọng trong đó khối cuối cùng có thể không thực thi. Nếu JVM hết bộ nhớ hoàn toàn, nó có thể thoát ra mà không bắt được hoặc cuối cùng xảy ra.
Cụ thể, tôi nhớ một dự án mà chúng tôi đã cố gắng sử dụng
catch (OutOfMemoryError oome) {
// do stuff
}
Điều này không hoạt động vì JVM không còn bộ nhớ để thực hiện khối bắt.
try { for (;;); } finally { System.err.println("?"); }
Trong trường hợp đó, cuối cùng sẽ không thực thi (trừ khi cái không dùng nữa Thread.stop
được gọi, hoặc tương đương, chẳng hạn, thông qua giao diện công cụ).
throw
, thì finally
khối sẽ thực thi như mong đợi. try { throw new ThreadDeath(); } finally { System.err.println("?"); }
Hướng dẫn Sun đã được trích dẫn sai ở đây trong chủ đề này.
Lưu ý: Nếu JVM thoát ra trong khi mã thử hoặc bắt đang được thực thi, thì khối cuối cùng sẽ không thực thi. Tương tự như vậy, nếu chuỗi thực thi mã try hoặc catch bị gián đoạn hoặc bị giết, khối cuối cùng sẽ không thực thi mặc dù toàn bộ ứng dụng vẫn tiếp tục.
Nếu bạn xem xét kỹ hướng dẫn sun cho khối cuối cùng, nó không nói "sẽ không thực thi" nhưng "có thể không thực thi" Đây là mô tả chính xác
Lưu ý: Nếu JVM thoát ra trong khi mã thử hoặc bắt đang được thực thi, thì khối cuối cùng có thể không thực thi. Tương tự như vậy, nếu chuỗi thực thi mã try hoặc catch bị gián đoạn hoặc bị giết, khối cuối cùng có thể không thực thi mặc dù toàn bộ ứng dụng vẫn tiếp tục.
Lý do rõ ràng cho hành vi này là, cuộc gọi đến system.exit () được xử lý trong một luồng hệ thống thời gian chạy, có thể mất thời gian để tắt jvm, trong khi đó, bộ lập lịch luồng có thể yêu cầu thực thi cuối cùng. Vì vậy, cuối cùng được thiết kế để luôn thực thi, nhưng nếu bạn đang tắt jvm, có thể xảy ra trường hợp jvm tắt trước khi cuối cùng được thực thi.
Ngoài ra nếu một bế tắc / sống động xảy ra bên trong try
khối.
Đây là mã chứng minh điều đó:
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();
}
}
Mã này tạo ra kết quả sau:
t1 inside lock1
t2 inside lock1
và "cuối cùng" không bao giờ được in
Nếu JVM thoát ra trong khi mã thử hoặc bắt đang được thực thi, thì khối cuối cùng có thể không thực thi. ( nguồn )
Tắt bình thường - điều này xảy ra khi luồng không phải daemon cuối cùng thoát HOẶC khi Runtime.exit () ( nguồn )
Khi một luồng thoát ra, JVM thực hiện kiểm kê các luồng đang chạy và nếu các luồng duy nhất còn lại là các luồng daemon, thì nó sẽ bắt đầu một quá trình tắt có trật tự. Khi JVM tạm dừng, mọi luồng daemon còn lại sẽ bị bỏ rơi, cuối cùng các khối không được thực thi, các ngăn xếp không được gỡ bỏ mà JVM chỉ thoát ra. Các luồng daemon nên được sử dụng một cách tiết kiệm, một số hoạt động xử lý có thể bị bỏ rơi một cách an toàn bất cứ lúc nào mà không cần dọn dẹp. Đặc biệt, rất nguy hiểm khi sử dụng các luồng daemon cho các tác vụ có thể thực hiện bất kỳ loại I / O nào. Các luồng Daemon được lưu tốt nhất cho các tác vụ "quản lý nội trợ", chẳng hạn như một luồng nền xóa định kỳ các mục đã hết hạn khỏi bộ nhớ đệm trong bộ nhớ. ( nguồn )
Ví dụ thoát chuỗi không phải daemon cuối cùng:
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.");
}
}
Đầu ra:
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
Trong các trường hợp sau, khối cuối cùng sẽ không được thực thi: -
System.exit(0)
được gọi từ try
khối. try
khối của bạnCũng có thể có các trường hợp rìa khác, nơi cuối cùng khối sẽ không được thực thi.
Có hai cách để dừng thực thi mã khối cuối cùng:
1. Sử dụng System.exit ();
2. Nếu bằng cách nào đó điều khiển thực thi không đạt để thử khối.
Xem:
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");
}
}
}
}
Tôi đã gặp một trường hợp rất cụ thể về khối cuối cùng không thực thi liên quan cụ thể đến khung chơi.
Tôi rất ngạc nhiên khi thấy rằng khối cuối cùng trong mã hành động bộ điều khiển này chỉ được gọi sau một Ngoại lệ, nhưng không bao giờ khi lệnh gọi thực sự thành công.
try {
InputStream is = getInputStreamMethod();
renderBinary(is, "out.zip");
catch (Exception e) {
e.printStackTrace();
} finally {
cleanUp();
}
Có lẽ luồng bị kết thúc hoặc một cái gì đó khi renderBinary () được gọi. Tôi nghi ngờ điều tương tự xảy ra với các lệnh gọi kết xuất () khác, nhưng tôi đã không xác minh điều đó.
Tôi đã giải quyết vấn đề bằng cách di chuyển renderBinary () đến sau lần thử / bắt. Điều tra sâu hơn cho thấy play cung cấp chú thích @Finally để tạo một phương thức được thực thi sau khi hành động của bộ điều khiển thực thi. Lưu ý ở đây là điều này sẽ được gọi sau khi thực hiện BẤT KỲ hành động nào trong bộ điều khiển, vì vậy nó có thể không phải lúc nào cũng là một lựa chọn tốt.
//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");
}
}