• 纠正关于线程的错误理解


    这里有个这样的程序,设计个简单的银行,假设某家银行,它可接受顾客的汇款,每做一次汇款,便可计算出汇款的总额。现在有两个客户,都对银行里同一个账户进行存钱取钱操作。测试synchronized关键字的作用。

    现在上代码:

    主要测试类:

    /**
     * 这个类就是拿来做测试跑程序用的
     * @author 85060
     *
     */
    public class MainTest2 {
        public static void main(String[] args) {
            EasyBank theBank = new EasyBank();//创建一个银行
            Client1 c1 = new Client1("c1", theBank);//创建客户1,是个runnable
            Client2 c2 = new Client2("c2", theBank);//创建客户2,是个runnable
            Thread c1Thread = new Thread(c1);//创建一个客户1的线程
            Thread c2Thread = new Thread(c2);//创建一个客户2的线程
            c1Thread.start();
            c2Thread.start();
            theBank.seeTheAccount();//在某一时刻查看银行账户的存款
            try {
                Thread.sleep(15000);//主线程睡个15秒
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            theBank.seeTheAccount();//15秒后再看一次(即最后银行的账户余额)
        }
    }

    银行类:

    /**
     * 这个类是个简单的银行
     * @author 85060
     *
     */
    public class EasyBank {
        public static double account = 0;
        
        public synchronized void deposit(Client client, double amount) {//存钱,带锁的,调用这个方法对象会被锁住
            account = account + amount;
            System.out.println("Client: "+client.name+"  The deposit operation has been done,the total account now is "+account);
        }
        
        public synchronized void withdraw(Client client, double amount) {//取钱,也是带锁的,如果没钱拿就等个10秒,看得出同步的效果
            if(account==0) {
                System.out.println("Client: "+client.name+"   Sorry,you don't have any money to withdraw!");
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            } else {
                account = account - amount;
                System.out.println("Client: "+client.name+"  The withdraw operation has been done,the total now is "+account);
            }
        }
        
        public void seeTheAccount() {
            System.out.println("The account is "+account);
        }
    }

    抽象客户类和两个客户的runnable类:

    /**
     * 这个类是取钱的客户
     * 
     * @author 85060
     * 
     */
    public abstract class Client {
        String name;
        EasyBank bank;
        
        public Client(String name, EasyBank bank) {
            this.name = name;
            this.bank = bank;
        }
    
        public void toDeposit(double amount) {
            bank.deposit(this, amount);
        }
    
        public void toWithDraw(double amount) {
            bank.withdraw(this, amount);
        }
    }
    
    class Client1 extends Client implements Runnable {
        
        public Client1(String name, EasyBank bank) {//存三次钱
            super(name, bank);
            // TODO Auto-generated constructor stub
        }
        
        @Override
        public void run() { // 
            // TODO Auto-generated method stub
            try {
                Thread.sleep(10);
                toDeposit(100);
                Thread.sleep((int) ((Math.random() * 1000)));
                toDeposit(100);
                //Thread.sleep((int) ((Math.random() * 1000)));// 休眠0~1秒
                toDeposit(100);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }// 休眠0~1秒
        }
    }
    
    class Client2 extends Client implements Runnable {//取两次钱存1次钱
        
        public Client2(String name, EasyBank bank) {
            super(name, bank);
            // TODO Auto-generated constructor stub
        }
        
        @Override
        public void run() { 
            // TODO Auto-generated method stub
            try {
                //Thread.sleep(10);
                toWithDraw(100);
                //Thread.sleep((int) ((Math.random() * 1000)));
                toWithDraw(100);
                //Thread.sleep((int) ((Math.random() * 1000)));// 休眠0~1秒
                toDeposit(100);
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }// 休眠0~1秒
        }
    }

    银行的存钱deposit方法和拿钱withdraw方法都加了synchronized关键字。

    一开始想着说,线程2(客户2)先访问嘛(因为可客户1先睡了个几毫秒,所以客户2会先拿到锁),然后客户2会走完他所有的run()方法后再到客户1走他的run方法。   就想着说理想的输出应该是Client 2: xxxxxxxxxxx    Client2:.............  2:...........   .......................   Client1:.............   Client1:.............

    结果是输出竟然是Client1和Client2交错出现的,然后我就很奇怪了。两个方法都带锁啊,不是会锁住对象的吗???

    然后发现每个线程都是是sleep()方法之后,后面的输出就换线程了。

    奇怪了?sleep不是只是暂停线程,但它不会把锁抛掉啊?!

    后面查了好久,测试了几次才意识到,这里的锁住对象,是方法的这块代码锁住对象。一个线程的run()方法里执行了那么多次deposit()和withdraw()方法。只是说当一个线程执行比如说deposit()方法的时候,其他线程不可能访问这个对象里的带有synchronized的方法。    但当线程执行完这个带锁的方法后,就自然会把锁放出,这个时候就再两个线程去抢锁。    然后如果你这个时候如果线程睡了sleep()了一会儿的话,锁肯定会被别的线程抢走啊!!所以就会出现交错出现的情况。

  • 相关阅读:
    python脚本 快速执行mapreduce程序
    ArrayList中contains()的使用方法
    利用jstl标签实现国际化
    device eth0 does not seem to be present, delaying initialization
    java中compareTo和compare方法之比较
    CentOS 7 NAT模式LVS搭建
    CentOS 7 DR模式LVS搭建
    CentOS 7 开机延迟解决办法
    CentOS 7 nginx+tomcat9 session处理方案之session复制
    Jumpserver(跳板机、堡垒机)启动jms Django连接mysql数据库报错
  • 原文地址:https://www.cnblogs.com/wangshen31/p/7666260.html
Copyright © 2020-2023  润新知