ACAC 账户取款(synchronized方法)

package AccountThread02;

public class Account {
    private String username;
    private double balance;
    Object obj = new Object();//实例变量

    public Account() {
    }

    public Account(String username, double balance) {
        this.username = username;
        this.balance = balance;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }

    public void withdraw(double money) {
        /**
         *
         * 1、该怎样让线程等待呢?
         *  synchronized方法,让进程等待
         *      用法:synchronized(共享){
         *          //线程同步代码块
         *      }
         *   ()里的数据时相当关键的,这个数据必须是多线程共享的数据(这里是账户对象)
         *    才能达到多线程排队
         *   ()中写什么?
         *      假设有1,2,3,4,5,五个线程
         *      如果希望1,2,3,排队就些1,2,3,共享的对象,而这个对象虽4和5是不共享的(比如,4和5的对象是另一个账户)
         *
         * 2、java中,每个对象都有“一把锁”,其实这把锁就是标记
         * 3、以下代码的执行原理:
         *      1、假设1和2线程并发,开始执行以下代码的时候,肯定有一个先一个后
         *
         *      2、假设1先执行,遇到了synchronized,这个时候自动找”后面共享对象“的对象锁
         *      找到之后,占有它,然后执行同步代码块中的程序,执行过程中一直占有着这把锁,直到
         *      同步代码块结束,这把锁才会释放
         *
         *      3、假设1占有了这把锁,2也遇到了synchronized关键字,也会去找有后面共享对象的这个锁
         *      但是发现这把锁已经被1占有,2只能在同步代码块外面等待1的结束,直到1把同步代码块执行结束
         *      1归还这个锁,进入同步代码块执行程序
         *      这样就达到了线程排队执行
         *    注意:这个共享对象一定要选好,一定是你需要排队执行这些线程对象所共享的
         */
        synchronized (this) {
       // synchronized (obj) { obj是可以的,是共享的,具体可以看图
       // synchronized ("abc"){ abc是可以的,但是所有的线程都会排队,因为所有的线程都共享字符串
        //字符串在常量池中,为所有线程的共享的
            double before = this.getBalance();
            double after = before - money;
            this.setBalance(after);
            System.out.println(Thread.currentThread().getName() + money + "取款成功," + "余额:" + this.getBalance());
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}

package AccountThread02;

public class AccountThread extends Thread{
    
    

    private Account account;

    public AccountThread(Account account) {
    
    
        this.account = account;
    }

    @Override
    public void run() {
    
    
        //睡眠一秒的话,绝对出错
        //在这里synchronized也行,扩大了同步范围,这个地方可不要写this,因为你共享的是Account对象
        //如果写this的话,那就是new了两把锁,没有意义


        synchronized (account){
    
    
            account.withdraw(5000);
        }
        account.withdraw(5000);

    }
}

package AccountThread02;

public class Test {
    
    
    public static void main(String[] args) {
    
    
        //创建账户对象(只有一个)
        Account aa = new Account("adff",10000);
        //创建两个线程
        Thread bb = new AccountThread(aa);
        Thread cc = new AccountThread(aa);

        bb.setName("线程一");
        cc.setName("线程二");
        bb.start();
        cc.start();

    }
}

package AccountThread03;

public class Account {
    
    
    private String username;
    private double balance;
    Object obj = new Object();//实例变量

    public Account() {
    
    
    }

    public Account(String username, double balance) {
    
    
        this.username = username;
        this.balance = balance;
    }

    public String getUsername() {
    
    
        return username;
    }

    public void setUsername(String username) {
    
    
        this.username = username;
    }

    public double getBalance() {
    
    
        return balance;
    }

    public void setBalance(double balance) {
    
    
        this.balance = balance;
    }

    /**
     * 在实例方法上可是使用synchronized
     *  synchronized一旦出现在实例方法上,一定锁的是this
     *  没得选,不能是其他的对象了,所以这种方式不灵活
     *
     *  另外一个缺点:synchronized出现在实例方法上,表示整个方法体都需要
     *  同步,可能会无故扩大同步的范围,导致程序的执行效率降低,所以这种方式不常用
     *
     *  优点:代码写的少,节俭
     *  如果共享的对象是this,并且需要同步的代码块是整个方法体,建议使用这种方式
     */
    public synchronized void withdraw(double money) {
    
    
            double before = this.getBalance();
            double after = before - money;
            this.setBalance(after);
            System.out.println(Thread.currentThread().getName() + money + "取款成功," + "余额:" + this.getBalance());
            try {
    
    
                Thread.sleep(2000);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
    }
}

package AccountThread03;

public class AccountThread extends Thread{
    
    

    private Account account;

    public AccountThread(Account account) {
    
    
        this.account = account;
    }

    @Override
    public void run() {
    
    
        //在这里synchronized也行,扩大了同步范围,这个地方可不要写this,因为你共享的是Account对象
        //如果写this的话,那就是new了两把锁,没有意义
        synchronized (account){
    
    
            account.withdraw(5000);
        }
        account.withdraw(5000);

    }
}

package AccountThread03;

public class Test {
    
    
    public static void main(String[] args) {
    
    
        //创建账户对象(只有一个)
        Account aa = new Account("adf",10000);
        //创建两个线程
        Thread bb = new AccountThread(aa);
        Thread cc = new AccountThread(aa);

        bb.setName("线程一");
        cc.setName("线程二");
        bb.start();
        cc.start();

    }
}

猜你喜欢

转载自blog.csdn.net/qq_44707513/article/details/110749329
今日推荐