接上一章没讲完的线程知识点中关于“死锁”的概念。
当线程进入不可运行状态时,其他线程无法访问那个加锁对象,所以一个线程会一直处于等待另一个线程的状态,而另一个线程又会处于等待下一个线程的状态,此时,所有的线程都陷入无休止的等待状态中,无法继续运行,这种情况就被称为线程的“死锁”。
线程死锁实例
package java_11_25;
public class ThreadDeadLock implements Runnable {
public static boolean flag = true;
private static Object A = new Object();
private static Object B = new Object();
public static void main(String[] args) {
Runnable r1 = new ThreadDeadLock();
Thread t1 = new Thread(r1);
Runnable r2 = new ThreadDeadLock();
Thread t2 = new Thread(r2);
t1.start();
t2.start();
}
public void AccessA() {
flag = false;
// 同步块
synchronized (A) {
System.out.println("线程t1 : 得到了A的锁");
try {
Thread.sleep(1000);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
System.out.println("线程t1 : 还想要得到B的锁");
synchronized (B) {
System.out.println("线程t1 : 我得到了B的锁");
}
}
}
public void AccessB() {
flag = true;
synchronized (B) {
System.out.println("线程t2 : 得到了B的锁");
try {
Thread.sleep(1000);
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
System.out.println("线程t2 : 还想要得到A的锁");
synchronized (A) {
System.out.println("线程t2 : 得到了A的锁");
}
}
}
@Override
public void run() {
// TODO Auto-generated method stub
if (flag) {
AccessA();
} else {
AccessB();
}
}
}
Java语言本身并没有提供防止死锁的具体方法,在具体程序设计时必须注意,以免出现死锁。通常注意不要使用stop()、suspend()、resume()及destroy()方法。
异常处理
在程序设计过程中通常会遇到两种不可避免的错误:编译错误和运行错误。
编译错误是由于编写的程序不符合程序的语法规定而导致的语法问题。
运行错误是指能够顺利地编译通过,在程序运行过程中产生的错误。
Java中的异常处理机制为程序提供了清晰的异常终止和错误处理的接口。当异常发生时,发生异常的方法抛出一个封装了错误消息的异常对象。此时程序不会继续运行,发生错误的方法也不会返回正常运行的值,异常处理机制开始搜索异常处理器来处理这种错误。
异常处理简单实例
package java_11_26;
public class ExceptionSimpleExample {
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
System.out.println("try语句的执行");
System.out.println("throw抛出异常");
throw (new Exception("抛出Exception异常实例!"));
} catch (Exception e) {
// TODO: handle exception
System.out.println("catch语句执行,捕获异常并处理");
// 输出异常对象的异常描述信息到控制台
System.out.println("toString()\n" + e.toString());
} finally {
System.out.println("finally语句的执行");
}
}
}
运行结果如图:
Java异常类
Java异常类都是由Throwable类派生而来的,派生出来的两个分支分别为Error类和Exception类。
异常类的层次结构如下所示:
Tips:Throwable类位于java.lang包中。
异常处理的方法
Exception异常类继承了父类Throwable的若干方法,包括:
public String toString();
返回异常对象的异常描述信息:
public String getMessage();
返回异常对象的详尽描述信息(包括输出异常的性质和类型):
public void printStackTrace();
使用异常类对象处理输出异常信息的实例:
package java_11_26;
public class ExceptionOutput {
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
int i = 5 / 0;
} catch (Exception e) {
// TODO: handle exception
System.out.println("toString()\n" + e.toString());
System.out.println("toString()\n" + e.getMessage());
System.out.println("printStackTrace()");
e.printStackTrace();
}
}
}
运行结果如下:
异常捕获
为了捕获异常,需要使用catch语句块配合try语句块。
try语句块内部如果出现异常,那么程序将跳过try语句块中出现异常的语句之后的其它代码,直接进入catch语句块内执行代码。
异常捕获处理语句块的实例:
package java_11_26;
public class CatchException {
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
int i = Integer.parseInt("tree");
// 输出信息,由于抛出异常,这句话将不显示
System.out.println("IllegalArgumentException will not show!" + i);
} catch (Exception e) { // 捕获异常
// TODO: handle exception
// 打印异常的类型及在程序中的位置等信息
System.out.println("printStackTrace()");
e.printStackTrace();
}
}
}
try-catch语句块可以嵌套使用。
实例如下:
package java_11_26;
public class TrynestdealException {
public static void main(String[] args) {
// TODO Auto-generated method stub
tryCatch();
}
private static void tryCatch() {
// TODO Auto-generated method stub
try {
try {
System.out.println("执行里层try块\n");
int inte = Integer.parseInt("pencil"); // 字符串转换成整数
System.out.println(inte);
} catch (ArrayIndexOutOfBoundsException e) {
// TODO: handle exception
System.out.println("执行里层catch1块\n");
System.out.println("捕获ArrayIndexOutOfBoundsException异常:" + e.getMessage());
} catch (ArithmeticException e) {
// TODO: handle exception
System.out.println("执行里层catch2块\n");
System.out.println("捕获ArithmeticException异常:" + e.getMessage());
}
} catch (ClassCastException ie) {
// TODO: handle exception
System.out.println("捕获外层异常ClassCastException:" + ie.getMessage());
} catch (NumberFormatException ie) {
// TODO: handle exception
System.out.println("捕获外层异常NumberFormatException:" + ie.getMessage());
}
}
}
运行结果如下:
注意,如果程序的主函数main()为静态函数,那么,由于静态函数不能调用非静态函数,所以tryCatch()函数必须定义成静态类型。