java 什么是可中断通道 Java异常机制是什么
很多朋友对于java 什么是可中断通道和Java异常机制是什么不太懂,今天就由小编来为大家分享,希望可以帮助到大家,下面一起来看看吧!
java程序死锁问题,怎么解决
在 IBM Bluemix云平台上开发并部署您的下一个应用。
开始您的试用
Java语言通过 synchronized关键字来保证原子性,这是因为每一个 Object都有一个隐含的锁,这个也称作监视器对象。在进入 synchronized之前自动获取此内部锁,而一旦离开此方式,无论是完成或者中断都会自动释放锁。显然这是一个独占锁,每个锁请求之间是互斥的。相对于众多高级锁(Lock/ReadWriteLock等),synchronized的代价都比后者要高。但是 synchronzied的语法比较简单,而且也比较容易使用和理解。Lock一旦调用了 lock()方法获取到锁而未正确释放的话很有可能造成死锁,所以 Lock的释放操作总是跟在 finally代码块里面,这在代码结构上也是一次调整和冗余。Lock的实现已经将硬件资源用到了极致,所以未来可优化的空间不大,除非硬件有了更高的性能,但是 synchronized只是规范的一种实现,这在不同的平台不同的硬件还有很高的提升空间,未来 Java锁上的优化也会主要在这上面。既然 synchronzied都不可能避免死锁产生,那么死锁情况会是经常容易出现的错误,下面具体描述死锁发生的原因及解决方法。
死锁描述
死锁是操作系统层面的一个错误,是进程死锁的简称,最早在 1965年由 Dijkstra在研究银行家算法时提出的,它是计算机操作系统乃至整个并发程序设计领域最难处理的问题之一。
事实上,计算机世界有很多事情需要多线程方式去解决,因为这样才能最大程度上利用资源,才能体现出计算的高效。但是,实际上来说,计算机系统中有很多一次只能由一个进程使用的资源的情况,例如打印机,同时只能有一个进程控制它。在多通道程序设计环境中,若干进程往往要共享这类资源,而且一个进程所需要的资源还很有可能不止一个。因此,就会出现若干进程竞争有限资源,又推进顺序不当,从而构成无限期循环等待的局面。我们称这种状态为死锁。简单一点描述,死锁是指多个进程循环等待它方占有的资源而无限期地僵持下去的局面。很显然,如果没有外力的作用,那么死锁涉及到的各个进程都将永远处于封锁状态。
系统发生死锁现象不仅浪费大量的系统资源,甚至导致整个系统崩溃,带来灾难性后果。所以,对于死锁问题在理论上和技术上都必须予以高度重视。
银行家算法
一个银行家如何将一定数目的资金安全地借给若干个客户,使这些客户既能借到钱完成要干的事,同时银行家又能收回全部资金而不至于破产。银行家就像一个操作系统,客户就像运行的进程,银行家的资金就是系统的资源。
银行家算法需要确保以下四点:
当一个顾客对资金的最大需求量不超过银行家现有的资金时就可接纳该顾客;
顾客可以分期贷款,但贷款的总数不能超过最大需求量;
当银行家现有的资金不能满足顾客尚需的贷款数额时,对顾客的贷款可推迟支付,但总能使顾客在有限的时间里得到贷款;
当顾客得到所需的全部资金后,一定能在有限的时间里归还所有的资金。
Java异常机制是什么
一、异常的关键字:
一般来说,异常的关键字有:try、catch、finally、throw、throws。
网上的资料对这几个关键字是这样解释的:
try: Opening exception-handling statement.
catch: Captures the exception.
finally: Runs its code before terminating the program.
throws: Lists the exceptions a method could throw.
Throw: Transfers control of the method to the exception handler.
try语句
try语句用大括号{}指定了一段代码,该段代码可能会抛弃一个或多个例外。
catch语句
catch语句的参数类似于方法的声明,包括一个例外类型和一个例外对象。例外类型必须为Throwable类的子类,它指明了catch语句所处理的例外类型,例外对象则由运行时系统在try所指定的代码块中生成并被捕获,大括号中包含对象的处理,其中可以调用对象的方法。
catch语句可以有多个,分别处理不同类的例外。Java运行时系统从上到下分别对每个catch语句处理的例外类型进行检测,直到找到类型相匹配的catch语句为止。这里,类型匹配指catch所处理的例外类型与生成的例外对象的类型完全一致或者是它的父类,因此,catch语句的排列顺序应该是从特殊到一般。也可以用一个catch语句处理多个例外类型,这时它的例外类型参数应该是这多个例外类型的父类,程序设计中要根据具体的情况来选择catch语句的例外处理类型。
finally语句
try所限定的代码中,当抛弃一个例外时,其后的代码不会被执行。通过finally语句可以指定一块代码。无论try所指定的程序块中抛弃或不抛弃例外,也无论catch语句的例外类型是否与所抛弃的例外的类型一致,finally所指定的代码都要被执行,它提供了统一的出口。通常在finally语句中可以进行资源的清除工作。如关闭打开的文件等。
throws语句
throws总是出现在一个函数头中,用来标明该成员函数可能抛出的各种异常。对大多数Exception子类来说,Java编译器会强迫你声明在一个成员函数中抛出的异常的类型。如果异常的类型是Error或 RuntimeException,或它们的子类,这个规则不起作用,因为这在程序的正常部分中是不期待出现的。如果你想明确地抛出一个RuntimeException,你必须用throws语句来声明它的类型
throw语句
throw总是出现在函数体中,用来抛出一个异常。程序会在throw语句后立即终止,它后面的语句执行不到,然后在包含它的所有try块中(可能在上层调用函数中)从里向外寻找含有与其匹配的catch子句的try块。
其实,我个人觉得,简单的来说:throws与throw从拼写上只相差一个s,但是功能、作用上有很大的区别。throws用于在方法和类处声明可能抛出的所有异常信息。throw而throw就是单个语句抛出异常,是指抛出的一个具体的异常类型,使用在方法(类)的内部。
如:
………………………………………………………………………………………………………
public class showUI throws Exception(){
public void tbstudy throws Exception(){
****;//
try{
/*这里是要处理的异常*/
}
Catch(Exception of){
System.out.println(of);//打印出异常
}
}
}
………………………………………………………………………………………………………
throws通常不用显示的捕获异常,可由系统自动将所有捕获的异常信息抛给上级方法(即调用该方法或类的所有地方);
throw则需要用户自己捕获相关的异常,而后再对其进行相关处理(如打印异常的地方,类型等),最后将处理后的异常信息抛出。
他们对异常处理方式也不同.throws对异常不处理,谁调用谁处理,throws的Exception的取值范围要大于方法内部异常的最大范围,而cathch的范围又要大于throws的Exception的范围;throw主动抛出自定义异常类对象。
二、异常继承体系
异常的继承结构
三、java处理异常方式
在java代码中如果发生异常,jvm(java虚拟机)会抛出异常对象,导致程序代码中断,这个时候jvm在做的操作就是:创建异常对象,然后抛出,比如:
1.int i= 1;
2.int j= 0;
3.int res= 0;
4.res= i/j;//除0错误
5.System.out.println(res);
这5句代码运行到第四句会中断,因为jvm抛出了异常
2.throw的作用:手动抛出异常。有时候有些错误在jvm看来不是错误,比如:
1. int age= 0;
2. age=-100;
3.System.out.println(age);
很正常的整形变量赋值,但是在我们眼中看来就不正常,谁的年龄会是负的呢?!所以我们需要自己手动引发异常,这就是throw的作用
int age= 0;
age=-100;
if(age<0){
Exception e= new Exception();//创建异常对象
throw e;//抛出异常
}
System.out.println(age);
java中的异常机制
异常机制是指当程序出现错误后,程序如何处理。具体来说,异常机制提供了程序退出的安全通道。当出现错误后,程序执行的流程发生改变,程序的控制权转移到异常处理器。
传统的处理异常的办法是,函数返回一个特殊的结果来表示出现异常(通常这个特殊结果是大家约定俗称的),调用该函数的程序负责检查并分析函数返回的结果。这样做有如下的弊端:例如函数返回-1代表出现异常,但是如果函数确实要返回-1这个正确的值时就会出现混淆;可读性降低,将程序代码与处理异常的代码混叠在一起;由调用函数的程序来分析错误,这就要求客户程序员对库函数有很深的了解。
在使用File类的方法时,如正在将U盘里面的照片复制到电脑里时,有人将U盘拔掉了。这时我们的复制程序就会出错,即抛出异常。当出现程序无法控制的外部环境问题(用户提供的文件不存在或者创建文件时已有同名文件存在,文件内容损坏,网络不可用...)时,JAVA就会用异常对象来描述。
异常情况通常有三大类:
(1)检查性异常:java.lang.Exception
(2)运行期异常:java.lang.RuntimeException
(3)错误:java.lang.Error
它们都是java.lang.Throwable类的子孙类。如右图:
Throwable类是 Java语言中所有错误和异常类的父类,对于具体的异常,不应该使用Throwable类,而应该使用其他三者之一。
检查性异常------程序正确,但因为外在的环境条件不满足引发。例如:用户错误及I/O问题----程序试图打开一个并不存在的远程Socket端口。这不是程序本身的逻辑错误,而很可能是远程机器名字错误(用户拼写错误)。对商用软件系统,程序开发者必须考虑并处理这个问题。JAVA编译器强制要求处理这类异常,如果不捕获这类异常,程序将不能被编译。
运行期异常------这意味着程序存在bug,如数组越界,0被除,入参不满足规范.....这类异常需要更改程序来避免,JAVA编译器强制要求处理这类异常。用来表示设计或实现方面的问题,如数组越界等。因为设计和实现正确的程序不会引发这类异常,所以常常不处理它。发生这类异常时,运行时环境会输出一条信息,提示用户修正错误。
错误------一般很少见,也很难通过程序解决。它可能源于程序的bug,但一般更可能源于环境问题,如内存耗尽。错误在程序中无须处理,而有运行环境处理。Error表示很难恢复的错误,如内存越界。一般不期望用户程序来处理,即使程序员有能力处理这种错误,也还是交给系统处理为好。
Java如何中断一个正在运行的线程
程序是很简易的然而在编程人员面前多线程呈现出了一组新的难题如果没有被恰当的解决将导致意外的行为以及细微的难以发现的错误
在本篇文章中我们针对这些难题之一如何中断一个正在运行的线程
背景中断(Interrupt)一个线程意味着在该线程完成任务之前停止其正在进行的一切有效地中止其当前的操作线程是死亡还是等待新的任务或是继续运行至下一步就取决于这个程序虽然初次看来它可能显得简单但是你必须进行一些预警以实现期望的结果你最好还是牢记以下的几点告诫
首先忘掉Thread stop方法虽然它确实停止了一个正在运行的线程然而这种方法是不安全也是不受提倡的这意味着在未来的JAVA版本中它将不复存在
一些轻率的家伙可能被另一种方法Thread interrupt所迷惑尽管其名称似乎在暗示著什么然而这种方法并不会中断一个正在运行的线程(待会将进一步说明)正如Listing A中描述的那样它创建了一个线程并且试图使用Thread interrupt方法停止该线程 Thread sleep()方法的调用为线程的初始化和中止提供了充裕的时间线程本身并不参与任何有用的操作
class Example extends Thread{ boolean stop=false; public static void main( String args[]) throws Exception{ Example thread= new Example(); System out println( Starting thread); thread start(); Thread sleep(); System out println( Interrupting thread); thread interrupt(); Thread sleep(); System out println( Stopping application);//System exit();} public void run(){ while(!stop){ System out println( Thread is running); long time= System currentTimeMillis(); while((System currentTimeMillis() time<)){}} System out println( Thread exiting under request);}}
如果你运行了Listing A中的代码你将在控制台看到以下输出
Starting thread Thread is running Thread is running Thread is running Interrupting thread Thread is running Thread is running Thread is running Stopping application Thread is running Thread is running Thread is running
甚至在Thread interrupt()被调用后线程仍然继续运行
真正地中断一个线程
中断线程最好的最受推荐的方式是使用共享变量(shared variable)发出信号告诉线程必须停止正在运行的任务线程必须周期性的核查这一变量(尤其在冗余操作期间)然后有秩序地中止任务 Listing B描述了这一方式
ListingBclassExample extendsThread{volatilebooleanstop=false;publicstaticvoidmain(Stringargs[])throwsException{Example thread=newExample();System out println( Startingthread);thread start();Thread sleep();System out println( Askingthreadtostop);thread stop=true;Thread sleep();System out println( Stoppingapplication);//System exit();}publicvoidrun(){while(!stop){System out println( Threadisrunning);longtime=System currentTimeMillis();while((System currentTimeMillis() time<)&&(!stop)){}}System out println( Threadexitingunderrequest);}}
运行Listing B中的代码将产生如下输出(注意线程是如何有秩序的退出的)
Startingthread Threadisrunning Threadisrunning Threadisrunning Askingthreadtostop Threadexitingunderrequest Stoppingapplication
虽然该方法要求一些编码但并不难实现同时它给予线程机会进行必要的清理工作这在任何一个多线程应用程序中都是绝对需要的请确认将共享变量定义成volatile类型或将对它的一切访问封入同步的块/方法(synchronized blocks/methods)中
到目前为止一切顺利!但是当线程等待某些事件发生而被阻塞又会发生什么?当然如果线程被阻塞它便不能核查共享变量也就不能停止这在许多情况下会发生例如调用Object wait() ServerSocket accept()和DatagramSocket receive()时这里仅举出一些
他们都可能永久的阻塞线程即使发生超时在超时期满之前持续等待也是不可行和不适当的所以要使用某种机制使得线程更早地退出被阻塞的状态
很不幸运不存在这样一种机制对所有的情况都适用但是根据情况不同却可以使用特定的技术在下面的环节我将解答一下最普遍的例子
使用Thread interrupt()中断线程
正如Listing A中所描述的 Thread interrupt()方法不会中断一个正在运行的线程这一方法实际上完成的是在线程受到阻塞时抛出一个中断信号这样线程就得以退出阻塞的状态更确切的说如果线程被Object wait Thread join和 Thread sleep三种方法之一阻塞那么它将接收到一个中断异常(InterruptedException)从而提早地终结被阻塞状态
因此如果线程被上述几种方法阻塞正确的停止线程方式是设置共享变量并调用interrupt()(注意变量应该先设置)如果线程没有被阻塞这时调用interrupt()将不起作用否则线程就将得到异常(该线程必须事先预备好处理此状况)接着逃离阻塞状态在任何一种情况中最后线程都将检查共享变量然后再停止 Listing C这个示例描述了该技术
ListingCclassExample extendsThread{volatilebooleanstop=false;publicstaticvoidmain(Stringargs[])throwsException{Example thread=newExample();System out println( Startingthread);thread start();Thread sleep();System out println( Askingthreadtostop);thread stop=true;//如果线程阻塞将不会检查此变量thread interrupt();Thread sleep();System out println( Stoppingapplication);//System exit();}publicvoidrun(){while(!stop){System out println( Threadrunning);try{Thread sleep();}catch(InterruptedExceptione){System out println( Threadinterrupted);}}System out println( Threadexitingunderrequest);}}
一旦Listing C中的Thread interrupt()被调用线程便收到一个异常于是逃离了阻塞状态并确定应该停止运行以上代码将得到下面的输出
Startingthread Threadrunning Threadrunning Threadrunning Askingthreadtostop Threadinterrupted Threadexitingunderrequest Stoppingapplication
中断I/O操作
然而如果线程在I/O操作进行时被阻塞又会如何?I/O操作可以阻塞线程一段相当长的时间特别是牵扯到网络应用时例如服务器可能需要等待一个请求(request)又或者一个网络应用程序可能要等待远端主机的响应
如果你正使用通道(channels)(这是在Java中引入的新的I/O API)那么被阻塞的线程将收到一个 ClosedByInterruptException异常如果情况是这样其代码的逻辑和第三个例子中的是一样的只是异常不同而已
但是你可能正使用Java之前就存在的传统的I/O而且要求更多的工作既然这样 Thread interrupt()将不起作用因为线程将不会退出被阻塞状态 Listing D描述了这一行为尽管interrupt()被调用线程也不会退出被阻塞状态
ListingDimportjava io*;classExample extendsThread{publicstaticvoidmain(Stringargs[])throwsException{Example thread=newExample();System out println( Startingthread);thread start();Thread sleep();System out println( Interruptingthread);thread interrupt();Thread sleep();System out println( Stoppingapplication);//System exit();}publicvoidrun(){ServerSocketsocket;try{socket=newServerSocket();}catch(IOExceptione){System out println( Couldnotcreatethesocket);return;}while(true){System out println( Waitingforconnection);try{Socketsock=socket accept();}catch(IOExceptione){System out println( accept()failedorinterrupted);}}}}
很幸运 Java平台为这种情形提供了一项解决方案即调用阻塞该线程的套接字的close()方法在这种情形下如果线程被I/O操作阻塞该线程将接收到一个SocketException异常这与使用interrupt()方法引起一个InterruptedException异常被抛出非常相似
唯一要说明的是必须存在socket的引用(reference)只有这样close()方法才能被调用这意味着socket对象必须被共享 Listing E描述了这一情形运行逻辑和以前的示例是相同的
ListingEimport*;importjava io*;classExample extendsThread{volatilebooleanstop=false;volatileServerSocketsocket;publicstaticvoidmain(Stringargs[])throwsException{Example thread=newExample();System out println( Startingthread);thread start();Thread sleep();System out println( Askingthreadtostop);thread stop=true;thread socket close();Thread sleep();System out println( Stoppingapplication);//System exit();}publicvoidrun(){try{socket=newServerSocket();}catch(IOExceptione){System out println( Couldnotcreatethesocket);return;}while(!stop){System out println( Waitingforconnection);try{Socketsock=socket accept();}catch(IOExceptione){System out println( accept()failedorinterrupted);}}System out println( Threadexitingunderrequest);}}
以下是运行Listing E中代码后的输出
Startingthread Waitingforconnection Askingthreadtostop accept()failedorinterrupted Threadexitingunderrequest Stoppingapplication
多线程是一个强大的工具然而它正呈现出一系列难题其中之一是如何中断一个正在运行的线程如果恰当地实现使用上述技术中断线程将比使用Java平台上已经提供的内嵌操作更为简单 lishixinzhi/Article/program/Java/gj/201311/27481java 什么是可中断通道和Java异常机制是什么的问题分享结束啦,以上的文章解决了您的问题吗?欢迎您下次再来哦!