请教JAVA多线程中死锁的问题。
package syn4;
/**
* 测试类
*/
public class TestAccount {
public static void main(String[] args) {
Accout a = new Accout();
StudentThread s = new StudentThread(a);
GenearchThread g = new GenearchThread(a);
}
}
package syn4;
/**
* 模拟学生线程
*/
public class StudentThread extends Thread {
Accout a;
public StudentThread(Accout a){
this.a = a;
start();
}
public void run(){
try{
while(true){
Thread.sleep(2000);
a.getMoney(); //取钱
}
}catch(Exception e){}
}
}
package syn4;
/**
* 家长线程
*/
public class GenearchThread extends Thread {
Accout a;
public GenearchThread(Accout a){
this.a = a;
start();
}
public void run(){
try{
while(true){
Thread.sleep(12000);
a.saveMoney(); //存钱
}
}catch(Exception e){}
}
}
package syn4;
/**
* 银行账户
*/
public class Accout {
int money = 0;
/**
* 取钱
* 如果账户没钱则等待,否则取出所有钱提醒存钱
*/
public synchronized void getMoney(){
System.out.println("准备取钱!");
try{
if(money == 0){
wait(); //等待
}
//取所有钱
System.out.println("剩余:" + money);
money -= 50;
//提醒存钱
notify();
}catch(Exception e){}
}
/**
* 存钱
* 如果有钱则等待,否则存入200提醒取钱
*/
public synchronized void saveMoney(){
System.out.println("准备存钱!");
try{
if(money != 0){
wait(); //等待
}
//取所有钱
money = 200;
System.out.println("存入:" + money);
//提醒存钱
notify();
}catch(Exception e){}
}
}
一,这是老师给的关于消费者生产者问题的代码。
二,我的理解是,当消费者取完最后一笔钱,执行wait()前,计算机分配的时间片段结束。计算机转而执行存钱的线程,存钱后notify()取钱线程,但由于此时取钱线程不处于wait()状态,notify()无效。然后计算机继续执行之前未完成的wait(),之后取钱线程遍一睡不醒,导致存钱线程循环完毕后也陷入等待状态,死锁就形成了。
三,因为对JAVA语言多线程的不熟悉,看到这段代码是糊涂万分,希望能得到一份简单易懂的解释。。。。 --------------------编程问答-------------------- "我的理解是,当消费者取完最后一笔钱,执行wait()前,计算机分配的时间片段结束。计算机转而执行存钱的线程,"
上面这句话, 消费者在synchronized void getMoney()这个同步方法里,不执行wait()语句的话,生产者因为得不到同步对象的锁,会在锁池池子里等待,是无法执行的。
参考一下:
http://blog.csdn.net/jiafu1115/article/details/6804386
--------------------编程问答--------------------
这么理解不对吧,执行wait()前,不可能切换线程,因为都是加锁的。
你这程序我感觉不会死锁,挺正常一个程序,请其他高手鉴定 --------------------编程问答--------------------
这位高手,你给的链接有个图,说线程有7种状态,但是《Java核心技术》这本书中说Java线程只有6种状态,以下是原文:
Threads can be in one of six states:
•New
• Runnable
• Blocked
•Waiting
• Timed waiting
•Terminated
Once you invoke the start method, the thread is in the runnable state. A runnable--------------------编程问答-------------------- 要是硬要说会出现死锁,我觉得那有可能是没有吧存钱或者取钱线程唤醒,而是唤醒了别的线程。那么就可能出现死锁了. --------------------编程问答-------------------- 说一下我的理解:
thread may or may not actually be running. It is up to the operating system to give
the thread time to run. (The Java specification does not call this a separate state,
though. A running thread is still in the runnable state.)
首先这里没有死锁,只有死循环,是很简单的生产者-消费者模拟。
wait()表示让出CPU使用权,让CPU执行其他thread,同时释放对象锁。
Account对象,分别有两个synchronized的方法,表示调用此方法时,account对象被锁定。
生产者,和消费者的构造方法里,调用了start()启动线程。
在测试类里, new了两个对象,其实只启动了2个thread(不算main线程)
1)当消费者第一次取钱时,money==0,此线程wait(),释放account对象
2)生产者存钱,存完一笔后,调用notify()唤醒其他线程,唤醒消费者。此时有2个线程同时使用CPU,但是money!=0时,生产者wait()
3)消费者享有CPU使用权,每次去50,每次调notify()唤醒生产者线程,但money!=0时,生产者继续wait()
...
LZ明白了吗? --------------------编程问答--------------------
我给的例子中,runnable 状态分开了。runnable and running.
"Once you invoke the start method, the thread is in the runnable state. A runnable
thread may or may not actually be running."
--------------------编程问答-------------------- 据我分析,不会有死锁的可能,wait()是会释放锁的。莫非楼主运行出现死锁?不可能吧 --------------------编程问答-------------------- 绝对不会有死锁!! --------------------编程问答-------------------- 1 wait 的虚假唤醒是存在的,建议放到循环中执行。
2 以下是简单jdk上面建议的生产者消费者的例子,使用ReentrantLock和condition来写。
--------------------编程问答-------------------- public synchronized void getMoney(){
class BoundedBuffer {
final Lock lock = new ReentrantLock();
final Condition notFull = lock.newCondition();
final Condition notEmpty = lock.newCondition();
final Object[] items = new Object[100];
int putptr, takeptr, count;
public void put(Object x) throws InterruptedException {
lock.lock();
try {
while (count == items.length)
notFull.await();
items[putptr] = x;
if (++putptr == items.length) putptr = 0;
++count;
notEmpty.signal();
} finally {
lock.unlock();
}
}
public Object take() throws InterruptedException {
lock.lock();
try {
while (count == 0)
notEmpty.await();
Object x = items[takeptr];
if (++takeptr == items.length) takeptr = 0;
--count;
notFull.signal();
return x;
} finally {
lock.unlock();
}
}
}
System.out.println("准备取钱!");
try{
if(money == 0){
wait(); //等待
}
看这一些代码,如果money为0的话你就要等待了,等待过程中是占有锁的,另一个线程是取不到这个锁的,而此时线程也是没有办法执行notify操作的,就死锁了。
public synchronized void saveMoney(){
System.out.println("准备存钱!");
try{
if(money != 0){
wait(); //等待
}
还有这个,都是一样的效果。 --------------------编程问答-------------------- 不会产生死锁。。。 --------------------编程问答-------------------- 我的理解是,当消费者取完最后一笔钱,执行wait()前,计算机分配的时间片段结束。计算机转而执行存钱的线程,存钱后notify()取钱线程,但由于此时取钱线程不处于wait()状态,notify()无效。然后计算机继续执行之前未完成的wait(),之后取钱线程遍一睡不醒,导致存钱线程循环完毕后也陷入等待状态,死锁就形成了。
当取钱完成之后,此时,存钱线程的断点在 wait()这里!
直到,取钱线程调用了notify
存钱现场才离开wait(),执行一个存钱的动作,而此时,取钱的线程的断点在 getMoney的wait 处。
不会死锁
如果你想死锁,
要抢夺多个资源。
补充:Java , Java SE