| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 1878 人关注过本帖
标题:请教有关使用synchronized修饰的方法,出现程序死锁的问题
只看楼主 加入收藏
mudi
Rank: 1
等 级:新手上路
帖 子:22
专家分:0
注 册:2018-12-19
结帖率:100%
收藏
已结贴  问题点数:20 回复次数:5 
请教有关使用synchronized修饰的方法,出现程序死锁的问题
当我运行下列程序时,发现出现了死锁的问题?还请论坛的前辈可以帮忙指点~谢谢!
服务端程序
程序代码:
import java.util.Arrays;

/**

 * a Bank with a number of bank accounts that uses Synchronization primitives

 * @author john

 *

 */
public class BankSynch {
    private final double[] accounts;
   

    /**
     * Construct the bank
     * @param n the number of accounts
     * @param initialBlance the initial balance for each account
     */
    public BankSynch(int n,double initialBalance) {
        accounts = new double[n];
        Arrays.fill(accounts, initialBalance);
    }
   

    /**
     * Transfer the money from one account to another
     * @param from the account transfer from
     * @param to the account transfer to
     * @param amount the amount to transfer
     * @throws InterruptedException

     */
    public synchronized void transfer(int from, int to, double amount) throws InterruptedException {
        while(accounts[from] < amount) {
            wait();
            System.out.println(Thread.currentThread());
            accounts[from] -= amount;
            System.out.printf("%10.2f from %d to %d",amount,from,to);
            accounts[to] += amount;
            System.out.printf("Total balance: %10.2f%n",getTotalBalance());
            notifyAll();
        }
    }
   

    /**
     * Get the sum of all accounts balance
     * @return the total balance
     */
    private Object getTotalBalance() {
        double sum = 0;
        for(double a : accounts) {
            sum += a;
        }
        return sum;
    }
   

    /**
     * Gets the number of accounts in the bank
     * @return the number of accounts
     */
    public int size() {
        return accounts.length;
    }

}
客户端程序
程序代码:
/**

 * This program shows data corruption when multiple thread access the dataStructure

 * @author john

 *

 */
public class UnsychBankAccountTest {
    public static final int NACCOUNTS =100;
    public static final double INITIAL_BALANCE =1000;
    public static final double MAX_AMOUNT = 1000;
    public static final int DELAY= 10;
   

    public static void main(String[] args) {
        BankSynch bank = new BankSynch(NACCOUNTS,INITIAL_BALANCE);
        for(int i =0;i<NACCOUNTS;i++) {
            int fromAccount = i;
            Runnable r = () ->{
                try {
                    while(true) {
                        int toAccount = (int)(bank.size()*Math.random());
                        double amount = MAX_AMOUNT * Math.random();
                        bank.transfer(fromAccount, toAccount, amount);
                        Thread.sleep((int)(DELAY*Math.random()));
                    }
                } catch (InterruptedException e) {
               

                }
            };
            Thread t = new Thread(r);
            t.start();
        }
    }
}

搜索更多相关主题的帖子: public double the int amount 
2019-03-17 14:58
rind
Rank: 5Rank: 5
等 级:贵宾
威 望:17
帖 子:49
专家分:368
注 册:2018-3-8
收藏
得分:20 
能不能把英文注释翻译一下?
平时就拿英文注释?

你的逻辑有问题。
死锁很正常。

transfer里面的代码显示
while的判断条件是指定账户的余额<转账金额时才执行。否则,方法结束。
这个逻辑就有明显问题。其他问题都是小问题。

弄好逻辑再说吧。

多看点基础的书。

程序代码:
public synchronized void transfer(int from, int to, double amount) throws InterruptedException {
    System.out.println(Thread.currentThread().getName() + "        BankSynch.transfer()   before");
//        while (accounts[from] < amount) {
//            System.out.println("BankSynch.transfer()");
//            wait();
//            System.out.println(Thread.currentThread());
//            accounts[from] -= amount;
//            System.out.printf("%10.2f from %d to %d", amount, from, to);
//            accounts[to] += amount;
//            System.out.printf("Total balance: %10.2f%n", getTotalBalance());
//            notifyAll();
//        }
    while (accounts[from] < amount) {
        wait();
    }
    System.out.println(Thread.currentThread());
    accounts[from] -= amount;
    System.out.printf("%10.2f from %d to %d", amount, from, to);
    accounts[to] += amount;
    System.out.printf("Total balance: %10.2f%n", getTotalBalance());
    notifyAll();
   

    System.out.println(Thread.currentThread().getName() + "         BankSynch.transfer() after");
}



[此贴子已经被作者于2019-3-22 14:23编辑过]


仅供参考,欢迎指正
2019-03-22 14:02
mudi
Rank: 1
等 级:新手上路
帖 子:22
专家分:0
注 册:2018-12-19
收藏
得分:0 
回复 2楼 rind
非常抱歉<(_ _)>,我的代码有错误,在while这个accounts[from]<amount这个条件后面本来有一条retuen语句
,我没有加上
2019-03-26 22:31
mudi
Rank: 1
等 级:新手上路
帖 子:22
专家分:0
注 册:2018-12-19
收藏
得分:0 
回复 2楼 rind
以下是我更改过来的程序,但是还是出现了死锁的问题,当我把Sychronized同步方法中的wait()和notifyAll()方法去除时,可以获得运行结果,但是有线程安全问题,
如果不去除, 但是我这里好像出现了死锁,不知道什么问题?
还请前辈帮忙指出问题:
 该程序的原本目的是为了验证Wait()和notifyAll()方法的使用;程序意思:银行当中有100个银行账户,每个账户中有初始余额1000元,随机从某一个取出账户中取出一部分金额,然后转入到另一个接收账户当中,
 以上操作会有同时多个线程同时进行,所以需要使用同步方法;


服务端代码
程序代码:
package thread;

import java.util.Arrays;

/**

 * a Bank with a number of bank accounts that uses Synchronization primitives、

 * 一个银行包含很多银行账户使用Sychronizeation


 * @author john

 *

 */
public class BankSynch {
    private final double[] accounts;
   

    /**
     * Construct the bank
     * @param n the number of accounts
     * @param initialBlance the initial balance for each account
     */
    public BankSynch(int n,double initialBalance) {
        accounts = new double[n];
        Arrays.fill(accounts, initialBalance);
    }
   

    /**
     * Transfer the money from one account to another
     * 该方法将一个账户的钱转入另一个账户
     * @param from the account transfer from
     * @param to the account transfer to
     * @param amount the amount to transfer
     * @throws InterruptedException

     */
    public synchronized void transfer(int from, int to, double amount) throws InterruptedException {
        while(accounts[from] < amount) {
            return;
        }
            wait();
            System.out.println(Thread.currentThread());
            accounts[from] -= amount;
            System.out.printf("%10.2f from %d to %d",amount,from,to);
            accounts[to] += amount;
            System.out.printf("Total balance: %10.2f%n",getTotalBalance());
            notifyAll();
       

    }
   

    /**
     * Get the sum of all accounts balance
     * 获取所有账户的余额
     * @return the total balance
     */
    private Object getTotalBalance() {
        double sum = 0;
        for(double a : accounts) {
            sum += a;
        }
        return sum;
    }
   

    /**
     * Gets the number of accounts in the bank
     * 获取银行当中所有账户的数目
     * @return the number of accounts
     */
    public int size() {
        return accounts.length;
    }

}

客户端代码
程序代码:
/**

 * This program shows data corruption when multiple thread access the dataStructure

 * 该程序展示了使用多线程访问数据结构时产生的数据冲突

 * @author john

 *

 */
public class UnsychBankAccountTest {
    public static final int NACCOUNTS =100;
    public static final double INITIAL_BALANCE =1000;
    public static final double MAX_AMOUNT = 1000;
    public static final int DELAY= 10;
   

    public static void main(String[] args) {
        BankSynch bank = new BankSynch(NACCOUNTS,INITIAL_BALANCE);
        for(int i =0;i<NACCOUNTS;i++) {
            int fromAccount = i;
            Runnable r = () ->{
                try {
                    while(true) {
                        int toAccount = (int)(bank.size()*Math.random());
                        double amount = MAX_AMOUNT * Math.random();
                        bank.transfer(fromAccount, toAccount, amount);
                        Thread.sleep((int)(DELAY*Math.random()));
                    }
                } catch (InterruptedException e) {
               

                }
            };
            Thread t = new Thread(r);
            t.start();
        }
    }
}

2019-03-26 22:49
rind
Rank: 5Rank: 5
等 级:贵宾
威 望:17
帖 子:49
专家分:368
注 册:2018-3-8
收藏
得分:0 
回复 4楼 mudi
首先,你需要弄清楚调用wait方法后,线程的状态。
以及如何改变线程的状态。

wait和notify/notifyAll顺序执行是有问题的。

然后,对情况的分类处理。

其实就几种特殊情况,主要是transfer方法需要讨论的:
1、转账金额<=账户余额
2、转账金额>账户余额

开两三个线程就能验证大多情况了。
开一百个线程,没必要一上来就弄这么多。

你要理清你的思路。

你的代码里:
对于1情况不会进入while循环,但是会立即调用wait方法。对于所有线程都是这么个情况。
然后没有线程去唤醒其他线程,所有线程阻塞。这个情况属于假死。
对于情况2会直接返回。

对于情况2的处理勉强能理解:余额不足、转账失败,但是没有提示。
对于情况1的逻辑就有点问题了。
如果对2的处理是你能接受的,那么处理1的话,就没必要使用wait和notifyAll了。也没必要使用while,if就足够。

程序代码:
    public synchronized void transfer(int from, int to, double amount) throws InterruptedException {
        //while (accounts[from] < amount) {
         if(accounts[from] < amount){
            return;
        }
//        wait();
        System.out.println(Thread.currentThread());
        accounts[from] -= amount;
        System.out.printf("%10.2f from %d to %d", amount, from, to);
        accounts[to] += amount;
        System.out.printf("Total balance: %10.2f%n", getTotalBalance());
//        notifyAll();
    }

如果想要情况2的处理为:余额不足,等待筹款到余额足够。那就参考2楼的代码。


[此贴子已经被作者于2019-3-27 09:10编辑过]


仅供参考,欢迎指正
2019-03-27 09:01
mudi
Rank: 1
等 级:新手上路
帖 子:22
专家分:0
注 册:2018-12-19
收藏
得分:0 
回复 5楼 rind
对wait方法使用我写错了地方,第二次检查也没有看出来,说明对该方法并没有理解透彻,还需多多学习,谢谢前辈
2019-03-27 11:50
快速回复:请教有关使用synchronized修饰的方法,出现程序死锁的问题
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.020975 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved