如何设计避免多线程编程中的死锁问题

多线程编程,需要注意的一个关键问题,就是死锁问题。对于初学者来说,很多人对于死锁只是存在于一个概念上的理解,一个线程需要的锁被另一个线程占用,而另一个线程又在等待其它锁的释放,最终形成等待循环,从而造成死锁,但是实际应用中究竟怎样的情况会形成死锁呢,我们又该在程序的设计中如何避免死锁?接下来通过一个例子来给大家一个直观的感受。

 

这是一个用筷子吃饭的例子,5个人吃饭,有5只筷子,每个人需要拿到2只筷子才能吃饭,吃完饭后需要放下筷子,另外的人才能吃。那么我们来看看,什么情况会出现死锁呢。为了便于理解,我们这里设定每个人吃饭时,先拿起左边的筷子,再去拿右边的筷子,这个时候,如果每个人都拿了左边的筷子,那么当他们去右边筷子的时候,所有的人都在等待后面的人放下左边的筷子,这个时候死锁就形成了。

 

那么我们如何去设计,以避免死锁呢?这个时候我们设定最后一个人不是从左边拿筷子,而是先从右边拿筷子,这样总有一个人可以拿到2个筷子,吃完以后释放筷子,从而所有的人都可以顺利吃到饭。这样就避免了死锁。

 

所以死锁问题关键是去解决一个资源的共享和互斥的问题,我们在设计逻辑的时候需要考虑到资源是否会存在无法释放的情况,从设计上去避免这种情况的出现。当然这只是一个简单的示例,希望能给大家一个启发,我们在实际的情况中场景可能比这里复杂很多,需要大家在设计的时候仔细考虑。



public class ChopStick {
private int id;
private boolean ifGet=false;
public ChopStick(int id){
this.id = id;
}
public synchronized void getStick() throws InterruptedException{
while(ifGet){
wait();
}
ifGet=true;
Thread.sleep(1000);//此处是增加获取筷子的时间,模拟创造死锁环境
}
public synchronized void dropStick(){
ifGet=false;
notifyAll();
System.out.println("release chopstick");
}

public boolean isIfGet() {
return ifGet;
}
public void setIfGet(boolean ifGet) {
this.ifGet = ifGet;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String toString(){
return (this.id+1)+"号筷子";
}

}



public class People implements Runnable{
private int id;
private ChopStick leftStick;
private ChopStick rightStick;


public People(int id,ChopStick left,ChopStick right){
this.leftStick=left;
this.rightStick=right;
this.id = id;
}
public void run() {
try {
this.leftStick.getStick();
System.out.println(this+" start get left "+leftStick+" done");
this.rightStick.getStick();
System.out.println(this+" start get right "+rightStick+" done");
System.out.println(this+" start eating");
pause();

this.leftStick.dropStick();
this.rightStick.dropStick();
} catch (InterruptedException e) {
System.out.println(this+" 通过中断异常退出");
e.printStackTrace();
}
}
/**
* 暂停,模拟吃饭
* @param pauseFactor
* @throws InterruptedException 
*/
public void pause() throws InterruptedException{
Thread.sleep(1000);
}

public ChopStick getLeftStick() {
return leftStick;
}
public void setLeftStick(ChopStick leftStick) {
this.leftStick = leftStick;
}
public ChopStick getRightStick() {
return rightStick;
}
public void setRightStick(ChopStick rightStick) {
this.rightStick = rightStick;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String toString(){
return (this.id+1)+"号";
}

}


import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class DinerHandler {
public static void main(String[] args){
int size=5;
ChopStick[] stickGroup = new ChopStick[size];
for(int i=0;i<size;i++){
stickGroup[i] = new ChopStick(i);
}
ExecutorService executorService= Executors.newCachedThreadPool();
for(int j=0;j<size;j++){
if(j<size-1){
executorService.execute(new People(j,stickGroup[j],stickGroup[(j+1)%size]));
}else{
executorService.execute(new People(j,stickGroup[(j+1)%size],stickGroup[j]));
}
}
executorService.shutdown();
}
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值