大橙子网站建设,新征程启航
为企业提供网站建设、域名注册、服务器等服务
死锁
创新互联公司从2013年成立,先为宁蒗等服务建站,宁蒗等地企业,进行企业商务咨询服务。为宁蒗企业网站制作PC+手机+微官网三网同步一站式服务解决您的所有建站问题。
死锁是这样一种情形:多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。
导致死锁的根源在于不适当地运用“synchronized”关键词来管理线程对特定对象的访问。“synchronized”关键词的作用是,确保在某个时刻只有一个线程被允许执行特定的代码块,因此,被允许执行的线程首先必须拥有对变量或对象的排他性的访问权。当线程访问对象时,线程会给对象加锁,而这个锁导致其它也想访问同一对象的线程被阻塞,直至第一个线程释放它加在对象上的锁。
由于这个原因,在使用“synchronized”关键词时,很容易出现两个线程互相等待对方做出某个动作的情形。代码一是一个导致死锁的简单例子。
//代码一
class Deadlocker {
int field_1;
private Object lock_1 = new int[1];
int field_2;
private Object lock_2 = new int[1];
public void method1(int value) {
“synchronized” (lock_1) {
“synchronized” (lock_2) {
field_1 = 0; field_2 = 0;
}
}
}
public void method2(int value) {
“synchronized” (lock_2) {
“synchronized” (lock_1) {
field_1 = 0; field_2 = 0;
}
}
}
}
参考代码一,考虑下面的过程:
◆ 一个线程(ThreadA)调用method1()。
◆ ThreadA在lock_1上同步,但允许被抢先执行。
◆ 另一个线程(ThreadB)开始执行。
◆ ThreadB调用method2()。
◆ ThreadB获得lock_2,继续执行,企图获得lock_1。但ThreadB不能获得lock_1,因为ThreadA占有lock_1。
◆ 现在,ThreadB阻塞,因为它在等待ThreadA释放lock_1。
◆ 现在轮到ThreadA继续执行。ThreadA试图获得lock_2,但不能成功,因为lock_2已经被ThreadB占有了。
◆ ThreadA和ThreadB都被阻塞,程序死锁。
当然,大多数的死锁不会这么显而易见,需要仔细分析代码才能看出,对于规模较大的多线程程序来说尤其如此。好的线程分析工具,例如JProbe Threadalyzer能够分析死锁并指出产生问题的代码位置。
隐性死锁
隐性死锁由于不规范的编程方式引起,但不一定每次测试运行时都会出现程序死锁的情形。由于这个原因,一些隐性死锁可能要到应用正式发布之后才会被发现,因此它的危害性比普通死锁更大。下面介绍两种导致隐性死锁的情况:加锁次序和占有并等待。
加锁次序
当多个并发的线程分别试图同时占有两个锁时,会出现加锁次序冲突的情形。如果一个线程占有了另一个线程必需的锁,就有可能出现死锁。考虑下面的情形,ThreadA和ThreadB两个线程分别需要同时拥有lock_1、lock_2两个锁,加锁过程可能如下:
◆ ThreadA获得lock_1;
◆ ThreadA被抢占,VM调度程序转到ThreadB;
◆ ThreadB获得lock_2;
◆ ThreadB被抢占,VM调度程序转到ThreadA;
◆ ThreadA试图获得lock_2,但lock_2被ThreadB占有,所以ThreadA阻塞;
◆ 调度程序转到ThreadB;
◆ ThreadB试图获得lock_1,但lock_1被ThreadA占有,所以ThreadB阻塞;
◆ ThreadA和ThreadB死锁。
必须指出的是,在代码丝毫不做变动的情况下,有些时候上述死锁过程不会出现,VM调度程序可能让其中一个线程同时获得lock_1和lock_2两个锁,即线程获取两个锁的过程没有被中断。在这种情形下,常规的死锁检测很难确定错误所在。
占有并等待
如果一个线程获得了一个锁之后还要等待来自另一个线程的通知,可能出现另一种隐性死锁,考虑代码二。
//代码二
public class queue {
static java.lang.Object queueLock_;
Producer producer_;
Consumer consumer_;
public class Producer {
void produce() {
while (!done) {
“synchronized” (queueLock_) {
produceItemAndAddItToQueue();
“synchronized” (consumer_) {
consumer_.notify();
}
}
}
}
public class Consumer {
consume() {
while (!done) {
“synchronized” (queueLock_) {
“synchronized” (consumer_) {
consumer_.wait();
}
removeItemFromQueueAndProcessIt();
}
}
}
}
}
}
在代码二中,Producer向队列加入一项新的内容后通知Consumer,以便它处理新的内容。问题在于,Consumer可能保持加在队列上的锁,阻止Producer访问队列,甚至在Consumer等待Producer的通知时也会继续保持锁。这样,由于Producer不能向队列添加新的内容,而Consumer却在等待Producer加入新内容的通知,结果就导致了死锁。
在等待时占有的锁是一种隐性的死锁,这是因为事情可能按照比较理想的情况发展—Producer线程不需要被Consumer占据的锁。尽管如此,除非有绝对可靠的理由肯定Producer线程永远不需要该锁,否则这种编程方式仍是不安全的。有时“占有并等待”还可能引发一连串的线程等待,例如,线程A占有线程B需要的锁并等待,而线程B又占有线程C需要的锁并等待等。
要改正代码二的错误,只需修改Consumer类,把wait()移出“synchronized”()即可。
line = bufferedReader.readLine();//死锁位置
会等待,所以会。
用另一个线程读、主线程检测是否命令终止了。
楼上的,如果是死循环,会一直输出,不会停止,明显是死锁。
楼主:你这个是死锁,主要就是出在循环的问题,你把super.notify();放在循环里就可以了。
一点一点讲,A线程进入synchronized代码块中,首先唤醒一个正在等待的线程,当前肯定是没有了,因为锁的原因,然后A线程进入循环,输出"线程A:10",进入等待。
此时执行的权限交给B线程,B线程进入synchronized代码块,执行super.notify();唤醒了A线程,但是由于同步机制,现在A处于就绪状态,然后B线程进入循环,输出“线程B:9”,进入等待,此前A线程已经唤醒了,执行权交给A线程,继续执行,又循环一次,输出“线程A:8”,然后进入等待,此时B现在也处于等待的状态。然后就死锁了。
楼主够通俗不?
额,这么简单,就直接定义一个类,该类随便定义实例化个Object对象,然后在类中再定义2个内部线程类,线程一,对object使用synchronized,在synchronized块中用个while(true)的死循环就好了,线程二,对object也是使用synchronized同步,至于synchronized块中干啥,你自己看着办,反正线程一死循环不会释放object对象锁,线程二是执行不到里面的代码块的
主线程保持着A对象的锁意思就是主线程正在处理A对象,其他线程不能处理,要等待主线程结束之后其他线程才能处理A对象。
同理副线程正在处理B对象,A不能处理,所以主线程结束不了,一直在等待。
两个线程都运行不下去了就叫做死锁,程序崩溃。
加锁的意思就是某线程正在处理某对象,其他线程不能处理。
手打不容易,明白不明白都给分吧- -、
1. 请把下面的java代码用伪代码写出来
伪代码(Pseudocode)是一种算法描述语言。
使用伪代码的目的是为了使被描述的算法可以容易地以任何一种编程语言(Pascal,C,Java,etc)实现。因此,伪代码必须结构清晰、代码简单、可读性好,并且类似自然语言。
介于自然语言与编程语言之间。以编程语言的书写形式指明算法职能。
使用伪代码, 不用拘泥于具体实现。相比程序语言(例如Java, C++,C, Dephi 等等)它更类似自然语言。
它是半角式化、不标准的语言。可以将整个算法运行过程的结构用接近自然语言的形式(可以使用任何一种你熟悉的文字,关键是把程序的意思表达出来)描述出来。
String path = "***"File f = new File(path);public void test (F f)File []fs = f遍历文件夹;for(。){ if(fs[i]是文件){ 输入 }else{ 递归test(fs[i]); }}。
2. JAVA 伪代码
提示输入一个大于2且11的数字
输入一整型数值给Vertices,
if(Vertices 3 || Vertices 11){
提示重新输入且应输入
退出程序
}else{
生成一个Vertices * Vertices 大小的数组Graph,
填充数组 :行号与列号相同填充0,其余填充10以内随机数
交换元素:以[i][j]位置的数值与[j][i]位置的数值互换
最后打印数组各元素
}
3. 请把下列用java代码 用伪代码写出来
伪代码(Pseudocode)是一种算法描述语言。使用伪代码的目的是为了使被描述的算法可以容易地以任何一种编程语言(Pascal,C,Java,etc)实现。因此,伪代码必须结构清晰、代码简单、可读性好,并且类似自然语言。 介于自然语言与编程语言之间。以编程语言的书写形式指明算法职能。使用伪代码, 不用拘泥于具体实现。相比程序语言(例如Java, C++,C, Dephi 等等)它更类似自然语言。它是半角式化、不标准的语言。可以将整个算法运行过程的结构用接近自然语言的形式(可以使用任何一种你熟悉的文字,关键是把程序的意思表达出来)描述出来。
String path = "***"
File f = new File(path);
public void test (F f)
File []fs = f遍历文件夹;
for(。){
if(fs[i]是文件){
输入
}else{
递归test(fs[i]);
}
}
4. 伪代码怎么写
伪代码(Pseudocode)是一种算法描述语言。
使用伪代码的目的是为了使被描述的算法可以容易地以任何一种编程语言(Pascal,C,Java,etc)实现。因此,伪代码必须结构清晰、代码简单、可读性好,并且类似自然语言。
介于自然语言与编程语言之间。 它以编程语言的书写形式指明算法的职能。
相比于程序语言(例如Java, C++,C, Dephi 等等)它更类似自然语言。它是半角式化、不标准的语言。
我们可以将整个算法运行过程的结构用接近自然语言的形式(这里,你可以使用任何一种你熟悉的文字,中文,英文 等等,关键是你把你程序的意思表达出来)描述出来. 使用伪代码, 可以帮助我们更好的表述算法, 不用拘泥于具体的实现. 人们在用不同的编程语言实现同一个算法时意识到,他们的实现(注意:这里是实现,不是功能)很不同。尤其是对于那些熟练于不同编程语言的程序员要理解一个(用其他编程语言编写的程序的)功能时可能很难,因为程序语言的形式限制了程序员对程序关键部分的理解。
这样伪代码就应运而生了。 当考虑算法功能(而不是其语言实现)时,伪代码常常得到应用。
计算机科学在教学中通常使用虚拟码,以使得所有的程序员都能理解。 综上,简单的说,让人便于理解的代码。
不依赖于语言的,用来表示程序执行过程,而不一定能编译运行的代码。在数据结构讲算法的时候用的很多。
5. 伪代码的写法
类Pascal语言的伪代码的语法规则是: 在伪代码中,每一条指令占一行(else if,例外)。指令后不跟任何符号(Pascal和C中语句要以分号结尾)。
伪代码实例如下:
IF 九点以前 THEN
do 私人事务;
ELSE 9点到18点 THEN
工作;
ELSE
下班;
END IF
这样不但可以达到文档的效果,同时可以节约时间。更重要的是,使结构比较清晰,表达方式更加直观。
伪代码(Pseudocode)是一种算法描述语言。使用伪代码的目的是为了使被描述的算法可以容易地以任何一种编程语言(Pascal,C,Java,etc)实现。因此,伪代码必须结构清晰、代码简单、可读性好,并且类似自然语言。 介于自然语言与编程语言之间。
它以编程语言的书写形式指明算法的职能。相比于程序语言(例如Java, C++,C, Dephi 等等)它更类似自然语言。它是半角式化、不标准的语言。
我们可以将整个算法运行过程的结构用接近自然语言的形式(这里,你可以使用任何一种你熟悉的文字,中文,英文 等等,关键是你把你程序的意思表达出来)描述出来。使用伪代码, 可以帮助我们更好的表述算法,不用拘泥于具体的实现。
6. 伪代码的写法
最低0.27元开通文库会员,查看完整内容 原发布者:wangwenjxnu 伪代码伪代码是用介于自然语言和计算机语言之间的文字和符号来描述算法。
每一行(或几行)表示一个基本操作。它不用图形符号,因此书写方便、格式紧凑,也比较好懂,便于向程序过渡。
伪代码的7个主要部分:(1)算法名称(2)指令序列(3)输入/输出(4)分支选择(5)赋值(6)循环(7)算法结束1.算法名称两种表示算法的伪代码:过程(Procedure)函数(Function)过程和函数的区别是:过程是执行一系列的操作,不需要返回操作的结果,无返回数据;函数是执行一系列的操作后,要将操作的结果返回,有返回数据。算法伪代码的书写规则:Procedure([])Function([])如:ProcedureHanoi_Tower()FunctionFac(x)表示名为Fac的一个函数。
FunctionProg(n)表示名为Prog的一个函数。2.指令序列指令序列是算法的主体。
指令序列的书写规则:用Begin作为开始、用End作为结束;用“{”作为开始、用“/}”作为结束。例如:Begin指令序列;End或者:{指令序列;/}3.输出/输出输入:Input输出:Output或Return4.分支选择两种分支:IfThen{指令序列/}IfThen{。