JavaSE进阶

15.5.4 练习2

模拟银行取钱的问题

1.定义一个Account类

1)该Account类封装了账户编号(String)和余额(double)两个属性

2)设置相应属性的getter和setter方法

3)提供无参和有两个参数的构造器

4)系统根据账号判断与用户是否匹配,需提供hashCode()和equals()方法的重写

2.提供一个取钱的线程类

1)提供了Account类的account属性和double类的取款额的属性

2)提供带线程名的构造方法

3)run()方法中提供取钱的操作

3.在主类中创建线程进行测试。考虑线程安全问题。

 

public class Account {

    private String accountId;

    private double balance;

 

    public Account() {

    }

 

    public Account(String accountId, double balance) {

        this.accountId = accountId;

        this.balance = balance;

    }

 

    public String getAccountId() {

        return accountId;

    }

 

    public void setAccountId(String accountId) {

        this.accountId = accountId;

    }

 

    public double getBalance() {

        return balance;

    }

 

    public void setBalance(double balance) {

        this.balance = balance;

    }

 

    public String toString() {

        return "Account [accountId=" + accountId + ", balance=" + balance + "]";

    }

 

    public int hashCode() {

        final int prime = 31;

        int result = 1;

        result = prime * result + ((accountId == null) ? 0 : accountId.hashCode());

        long temp;

        temp = Double.doubleToLongBits(balance);

        result = prime * result + (int) (temp ^ (temp >>> 32));

        return result;

    }

 

    public boolean equals(Object obj) {

        if (this == obj)

            return true;

        if (obj == null)

            return false;

        if (getClass() != obj.getClass())

            return false;

        Account other = (Account) obj;

        if (accountId == null) {

            if (other.accountId != null)

                return false;

        } else if (!accountId.equals(other.accountId))

            return false;

        if (Double.doubleToLongBits(balance) != Double.doubleToLongBits(other.balance))

            return false;

        return true;

    }

 

    public class WithDrawThread extends Thread {

        Account account;

        // 要取款的额度

        double withDraw;

 

        public WithDrawThread(String name, Account account, double amt) {

            super(name);

            this.account = account;

            this.withDraw = amt;

        }

 

        public void run() {

            synchronized (account) {

                if (account.getBalance() > withDraw) {

                    System.out.println(Thread.currentThread().getName() + ":取款成功,取现的金额为:" + withDraw);

                    try {

                        Thread.sleep(50);

                    } catch (InterruptedException e) {

                        e.printStackTrace();

                    }

                    account.setBalance(account.getBalance() - withDraw);

                } else {

                    System.out.println("取现额度超过账户余额,取款失败");

                }

                System.out.println("现在账户的余额为:" + account.getBalance());

            }

        }

    }

 

    public class WithDrawThread extends Thread {

        Account account;

        // 要取款的额度

        double withDraw;

 

        public WithDrawThread(String name, Account account, double amt) {

            super(name);

            this.account = account;

            this.withDraw = amt;

        }

 

        public void run() {

            synchronized (account) {

                if (account.getBalance() > withDraw) {

                    System.out.println(Thread.currentThread().getName() + ":取款成功,取现的金额为:" + withDraw);

                    try {

                        Thread.sleep(50);

                    } catch (InterruptedException e) {

                        e.printStackTrace();

                    }

                    account.setBalance(account.getBalance() - withDraw);

                } else {

                    System.out.println("取现额度超过账户余额,取款失败");

                }

                System.out.println("现在账户的余额为:" + account.getBalance());

            }

        }

    }

}public class TestWithDrawThread {

    public static void main(String[] args) {

        Account account = new Account("1234567", 10000);

        Thread t1 = new WithDrawThread("小明", account, 8000);

        Thread t2 = new WithDrawThread("小明's wife", account, 2800);

        t1.start();

        t2.start();

    }

}

 

15.6 线程池

        系统启动一个新线程的成本是比较高的,因为它涉及与os交互。这种情况下,系统启动时即创建大量空闲的线程,就可以很好地提高性能,尤其是当程序需要创建大量生存期很短暂的线程时。

        除此之外,使用线程池可以有效地控制系统中并发线程的数量。避免因并发创建的线程过多,导致系统性能下降,JVM崩溃。

        Java 5以前,需要手动创建自己的线程池;Java 5开始,新增了Executors工厂类产生线程池。

使用线程池执行线程任务的步骤如下:

1.调用Executors 类的静态方法newFixedThreadPool(int nThreads),创建一个可重用的、具有固定线程数的线程池ExecutorService对象

2.创建Runnable实例,作为线程执行任务

3.调用ExecutorService对象的submit()提交Runnable实例

4.调用ExecutorService对象的shutDown()方法关闭线程池。