业务示例
父母是生产者,定期往学生卡里打1元生活费。学生每次消费1元。为了防止学生乱花钱,卡里余额大于5元的时候,暂停存钱。
父母总计会存入20元,学生消费20元。
blockingQueue
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
/**
* BlockingQueue
*/
public class BankcardTest6 {
Bankcard bankcard = new Bankcard();
Parent parent = new Parent(bankcard);
Son son = new Son(bankcard);
public void run1(){
for (int k = 0; k < 20; k++) {
try {
parent.deposit(1);
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void run2(){
for (int k = 0; k < 20; k++) {
try {
son.withdraw(1);
//TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws InterruptedException {
BankcardTest6 bankcardTes6 = new BankcardTest6();
new Thread(bankcardTes6::run1,"父母线程1").start();
new Thread(bankcardTes6::run1,"父母线程2").start();
new Thread(bankcardTes6::run2,"学生线程1").start();
new Thread(bankcardTes6::run2,"学生线程2").start();
}
}
class Bankcard{
private BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(5);
/**
* 往银行卡存钱
* @param money
*/
public void deposit(int money) throws InterruptedException {
queue.put(money);
System.out.println(Thread.currentThread().getName() + "存入" + money + ",还剩" + queue.size());
}
/**
* 从银行卡取钱
* @param money
*/
public void withdraw(int money) throws InterruptedException {
int m = queue.take();
System.out.println(Thread.currentThread().getName() + "取出" + m + "还剩" + queue.size());
}
}
class Parent{
private Bankcard bankcard;
public Parent(Bankcard bankCard){
this.bankcard = bankCard;
}
public void deposit(int money) throws InterruptedException {
this.bankcard.deposit(money);
}
}
class Son{
private Bankcard bankcard;
public Son(Bankcard bankCard){
this.bankcard = bankCard;
}
public void withdraw(int money) throws InterruptedException {
this.bankcard.withdraw(money);
}
}
运行结果
父母线程1存入1,还剩1
父母线程2存入1,还剩2
学生线程1取出1还剩1
学生线程1取出1还剩0
父母线程2存入1,还剩2
父母线程1存入1,还剩2
学生线程1取出1还剩1
学生线程2取出1还剩0
父母线程2存入1,还剩1
学生线程2取出1还剩0
学生线程1取出1还剩1
父母线程1存入1,还剩2
父母线程2存入1,还剩2
学生线程2取出1还剩1
父母线程1存入1,还剩2
学生线程1取出1还剩0
父母线程2存入1,还剩2
学生线程1取出1还剩0
学生线程2取出1还剩1
父母线程1存入1,还剩2
父母线程2存入1,还剩1
学生线程2取出1还剩0
父母线程1存入1,还剩1
学生线程1取出1还剩0
父母线程2存入1,还剩1
学生线程1取出1还剩0
学生线程2取出1还剩1
父母线程1存入1,还剩2
父母线程1存入1,还剩2
学生线程2取出1还剩0
学生线程1取出1还剩1
父母线程2存入1,还剩2
父母线程2存入1,还剩2
学生线程1取出1还剩0
学生线程2取出1还剩1
父母线程1存入1,还剩2
父母线程1存入1,还剩1
学生线程2取出1还剩0
学生线程1取出1还剩1
父母线程2存入1,还剩1
父母线程1存入1,还剩2
学生线程1取出1还剩0
学生线程2取出1还剩1
父母线程2存入1,还剩2
父母线程2存入1,还剩1
学生线程2取出1还剩0
学生线程1取出1还剩1
父母线程1存入1,还剩1
父母线程2存入1,还剩2
学生线程2取出1还剩1
父母线程1存入1,还剩2
学生线程1取出1还剩0
父母线程1存入1,还剩2
学生线程1取出1还剩0
学生线程2取出1还剩1
父母线程2存入1,还剩2
父母线程1存入1,还剩2
学生线程2取出1还剩0
学生线程1取出1还剩1
父母线程2存入1,还剩2
父母线程1存入1,还剩2
学生线程1取出1还剩0
学生线程2取出1还剩1
父母线程2存入1,还剩2
父母线程1存入1,还剩2
学生线程1取出1还剩0
学生线程2取出1还剩0
父母线程2存入1,还剩2
父母线程2存入1,还剩2
学生线程2取出1还剩0
学生线程1取出1还剩1
父母线程1存入1,还剩2
父母线程2存入1,还剩2
学生线程1取出1还剩0
学生线程2取出1还剩1
父母线程1存入1,还剩2
父母线程1存入1,还剩2
学生线程2取出1还剩1
父母线程2存入1,还剩2
学生线程2取出1还剩0
synchronized + wait/notify
一对父母供应一个学生
import java.util.concurrent.TimeUnit;
/**
* 生产者、消费者写法一:synchronized
*/
public class BankcardTest1 {
Bankcard bankcard = new Bankcard();
Parent parent = new Parent(bankcard);
Son son = new Son(bankcard);
public void run1(){
Thread.currentThread().setName("父母线程");
for (int k = 0; k < 20; k++) {
try {
parent.deposit(1);
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void run2(){
Thread.currentThread().setName("学生线程");
for (int k = 0; k < 20; k++) {
try {
son.withdraw(1);
//TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
BankcardTest1 bankcardTest1 = new BankcardTest1();
new Thread(bankcardTest1::run1,"父母线程").start();
new Thread(bankcardTest1::run2,"学生线程").start();
}
}
class Bankcard{
private int money;
/**
* 往银行卡存钱
* @param money
*/
public synchronized void deposit(int money) throws InterruptedException {
if (this.money >= 5){
System.out.println("余额已经超出5,暂不继续存钱");
this.wait();
}else{
this.money += money;
System.out.println(Thread.currentThread().getName() + "存入" + money + ",还剩" + this.money);
this.notifyAll();
}
}
/**
* 从银行卡取钱
* @param money
*/
public synchronized void withdraw(int money) throws InterruptedException {
if(this.money < money){
System.out.println(Thread.currentThread().getName() + "要取出" + money+",银行卡余额不足!");
this.wait();
}else{
this.money -= money;
System.out.println(Thread.currentThread().getName() + "取出" + money + "还剩" + this.money);
this.notifyAll();
}
}
}
class Parent{
private Bankcard bankcard;
public Parent(Bankcard bankCard){
this.bankcard = bankCard;
}
public void deposit(int money) throws InterruptedException {
this.bankcard.deposit(money);
}
}
class Son{
private Bankcard bankcard;
public Son(Bankcard bankCard){
this.bankcard = bankCard;
}
public void withdraw(int money) throws InterruptedException {
this.bankcard.withdraw(money);
}
}
父母线程存入1,还剩1
学生线程取出1还剩0
学生线程要取出1,银行卡余额不足!
父母线程存入1,还剩1
学生线程取出1还剩0
学生线程要取出1,银行卡余额不足!
父母线程存入1,还剩1
学生线程取出1还剩0
学生线程要取出1,银行卡余额不足!
父母线程存入1,还剩1
学生线程取出1还剩0
学生线程要取出1,银行卡余额不足!
父母线程存入1,还剩1
学生线程取出1还剩0
学生线程要取出1,银行卡余额不足!
父母线程存入1,还剩1
学生线程取出1还剩0
学生线程要取出1,银行卡余额不足!
父母线程存入1,还剩1
学生线程取出1还剩0
学生线程要取出1,银行卡余额不足!
父母线程存入1,还剩1
学生线程取出1还剩0
学生线程要取出1,银行卡余额不足!
父母线程存入1,还剩1
学生线程取出1还剩0
学生线程要取出1,银行卡余额不足!
父母线程存入1,还剩1
学生线程取出1还剩0
学生线程要取出1,银行卡余额不足!
父母线程存入1,还剩1
父母线程存入1,还剩2
父母线程存入1,还剩3
父母线程存入1,还剩4
父母线程存入1,还剩5
余额已经超出5,暂不继续存钱
控制台一直停留在这,无法继续往下执行。
问题出在if else:
/**
* 往银行卡存钱
* @param money
*/
public synchronized void deposit(int money) throws InterruptedException {
if (this.money >= 5){
System.out.println("余额已经超出5,暂不继续存钱");
this.wait();
}else{
this.money += money;
System.out.println(Thread.currentThread().getName() + "存入" + money + ",还剩" + this.money);
this.notifyAll();
}
}
当Parents线程wait()再次被notify时,无法进入else语句,正常往卡里存钱,所以应当修改如下:
import com.sss.concurrency.producer_and_consumer.test1.BankcardTest1;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;
/**
* 生产者、消费者写法一:synchronized
*/
public class BankcardTest2 {
Bankcard bankcard = new Bankcard();
Parent parent = new Parent(bankcard);
Son son = new Son(bankcard);
public void run1(){
Thread.currentThread().setName("父母线程");
for (int k = 0; k < 20; k++) {
try {
parent.deposit(1);
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void run2(){
Thread.currentThread().setName("学生线程");
for (int k = 0; k < 20; k++) {
try {
son.withdraw(1);
//TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
BankcardTest2 bankcardTest2 = new BankcardTest2();
new Thread(bankcardTest2::run1,"父母线程").start();
new Thread(bankcardTest2::run2,"学生线程").start();
}
}
class Bankcard{
private int money;
/**
* 往银行卡存钱
* @param money
*/
public synchronized void deposit(int money) throws InterruptedException {
if (this.money >= 5){
System.out.println("余额已经超出5,暂不继续存钱");
this.wait();
}
this.money += money;
System.out.println(Thread.currentThread().getName() + "存入" + money + ",还剩" + this.money);
this.notifyAll();
}
/**
* 从银行卡取钱
* @param money
*/
public synchronized void withdraw(int money) throws InterruptedException {
if(this.money < money){
System.out.println(Thread.currentThread().getName() + "要取出" + money+",银行卡余额不足!");
this.wait();
}
this.money -= money;
System.out.println(Thread.currentThread().getName() + "取出" + money + "还剩" + this.money);
this.notifyAll();
}
}
class Parent{
private Bankcard bankcard;
public Parent(Bankcard bankCard){
this.bankcard = bankCard;
}
public void deposit(int money) throws InterruptedException {
this.bankcard.deposit(money);
}
}
class Son{
private Bankcard bankcard;
public Son(Bankcard bankCard){
this.bankcard = bankCard;
}
public void withdraw(int money) throws InterruptedException {
this.bankcard.withdraw(money);
}
}
这次无论怎么运行,进程都会正常停止,父母总共存入20元,学生消费20元。
2对父母供应2对学生的时候会出问题
2对父母总共要存入40元。
import java.util.concurrent.TimeUnit;
/**
* 生产者、消费者写法一:synchronized
*/
public class BankcardTest3 {
Bankcard bankcard = new Bankcard();
Parent parent = new Parent(bankcard);
Son son = new Son(bankcard);
public void run1(){
for (int k = 0; k < 20; k++) {
try {
parent.deposit(1);
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void run2(){
for (int k = 0; k < 20; k++) {
try {
son.withdraw(1);
//TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
BankcardTest3 bankcardTest3 = new BankcardTest3();
new Thread(bankcardTest3::run1,"父母线程1").start();
new Thread(bankcardTest3::run1,"父母线程2").start();
new Thread(bankcardTest3::run2,"学生线程1").start();
new Thread(bankcardTest3::run2,"学生线程2").start();
}
}
class Bankcard{
private int money;
/**
* 往银行卡存钱
* @param money
*/
public synchronized void deposit(int money) throws InterruptedException {
if (this.money >= 5){
System.out.println("余额已经超出5,暂不继续存钱");
this.wait();
}
this.money += money;
System.out.println(Thread.currentThread().getName() + "存入" + money + ",还剩" + this.money);
this.notifyAll();
}
/**
* 从银行卡取钱
* @param money
*/
public synchronized void withdraw(int money) throws InterruptedException {
if(this.money < money){
System.out.println(Thread.currentThread().getName() + "要取出" + money+",银行卡余额不足!");
this.wait();
}
this.money -= money;
System.out.println(Thread.currentThread().getName() + "取出" + money + "还剩" + this.money);
this.notifyAll();
}
}
class Parent{
private Bankcard bankcard;
public Parent(Bankcard bankCard){
this.bankcard = bankCard;
}
public void deposit(int money) throws InterruptedException {
this.bankcard.deposit(money);
}
}
class Son{
private Bankcard bankcard;
public Son(Bankcard bankCard){
this.bankcard = bankCard;
}
public void withdraw(int money) throws InterruptedException {
this.bankcard.withdraw(money);
}
}
父母线程1存入1,还剩1
父母线程2存入1,还剩2
学生线程1取出1还剩1
学生线程1取出1还剩0
学生线程1要取出1,银行卡余额不足!
学生线程2要取出1,银行卡余额不足!
父母线程2存入1,还剩1
学生线程2取出1还剩0
学生线程2要取出1,银行卡余额不足!
学生线程1取出1还剩-1
学生线程1要取出1,银行卡余额不足!
父母线程1存入1,还剩0
学生线程1取出1还剩-1
学生线程1要取出1,银行卡余额不足!
学生线程2取出1还剩-2
学生线程2要取出1,银行卡余额不足!
学生线程1取出1还剩-3
学生线程1要取出1,银行卡余额不足!
学生线程2取出1还剩-4
学生线程2要取出1,银行卡余额不足!
学生线程1取出1还剩-5
学生线程1要取出1,银行卡余额不足!
学生线程2取出1还剩-6
学生线程2要取出1,银行卡余额不足!
学生线程1取出1还剩-7
学生线程1要取出1,银行卡余额不足!
学生线程2取出1还剩-8
学生线程2要取出1,银行卡余额不足!
学生线程1取出1还剩-9
学生线程1要取出1,银行卡余额不足!
学生线程2取出1还剩-10
学生线程2要取出1,银行卡余额不足!
学生线程1取出1还剩-11
学生线程1要取出1,银行卡余额不足!
学生线程2取出1还剩-12
学生线程2要取出1,银行卡余额不足!
学生线程1取出1还剩-13
学生线程1要取出1,银行卡余额不足!
学生线程2取出1还剩-14
学生线程2要取出1,银行卡余额不足!
学生线程1取出1还剩-15
学生线程1要取出1,银行卡余额不足!
学生线程2取出1还剩-16
学生线程2要取出1,银行卡余额不足!
学生线程1取出1还剩-17
学生线程1要取出1,银行卡余额不足!
学生线程2取出1还剩-18
学生线程2要取出1,银行卡余额不足!
学生线程1取出1还剩-19
学生线程1要取出1,银行卡余额不足!
学生线程2取出1还剩-20
学生线程2要取出1,银行卡余额不足!
学生线程1取出1还剩-21
学生线程1要取出1,银行卡余额不足!
学生线程2取出1还剩-22
学生线程2要取出1,银行卡余额不足!
学生线程1取出1还剩-23
学生线程1要取出1,银行卡余额不足!
学生线程2取出1还剩-24
学生线程2要取出1,银行卡余额不足!
学生线程1取出1还剩-25
学生线程1要取出1,银行卡余额不足!
学生线程2取出1还剩-26
学生线程2要取出1,银行卡余额不足!
学生线程1取出1还剩-27
学生线程1要取出1,银行卡余额不足!
学生线程2取出1还剩-28
学生线程2要取出1,银行卡余额不足!
学生线程1取出1还剩-29
学生线程1要取出1,银行卡余额不足!
学生线程2取出1还剩-30
学生线程2要取出1,银行卡余额不足!
学生线程1取出1还剩-31
学生线程1要取出1,银行卡余额不足!
学生线程2取出1还剩-32
学生线程2要取出1,银行卡余额不足!
学生线程1取出1还剩-33
学生线程2取出1还剩-34
学生线程2要取出1,银行卡余额不足!
父母线程1存入1,还剩-33
学生线程2取出1还剩-34
学生线程2要取出1,银行卡余额不足!
父母线程2存入1,还剩-33
学生线程2取出1还剩-34
父母线程2存入1,还剩-33
父母线程1存入1,还剩-32
父母线程2存入1,还剩-31
父母线程1存入1,还剩-30
父母线程2存入1,还剩-29
父母线程1存入1,还剩-28
父母线程1存入1,还剩-27
父母线程2存入1,还剩-26
父母线程1存入1,还剩-25
父母线程2存入1,还剩-24
父母线程2存入1,还剩-23
父母线程1存入1,还剩-22
父母线程2存入1,还剩-21
父母线程1存入1,还剩-20
父母线程2存入1,还剩-19
父母线程1存入1,还剩-18
父母线程2存入1,还剩-17
父母线程1存入1,还剩-16
父母线程2存入1,还剩-15
父母线程1存入1,还剩-14
父母线程1存入1,还剩-13
父母线程2存入1,还剩-12
父母线程2存入1,还剩-11
父母线程1存入1,还剩-10
父母线程2存入1,还剩-9
父母线程1存入1,还剩-8
父母线程2存入1,还剩-7
父母线程1存入1,还剩-6
父母线程2存入1,还剩-5
父母线程1存入1,还剩-4
父母线程2存入1,还剩-3
父母线程1存入1,还剩-2
父母线程2存入1,还剩-1
父母线程1存入1,还剩0
可以看到出现了负数,原因在于当多个线程wait()被notify唤醒时,不会再判断条件是否满足。直接从wait往下执行了。在jdk中对wait方法有段描述:
/**
* Causes the current thread to wait until another thread invokes the
* {@link java.lang.Object#notify()} method or the
* {@link java.lang.Object#notifyAll()} method for this object.
* In other words, this method behaves exactly as if it simply
* performs the call {@code wait(0)}.
* <p>
* The current thread must own this object's monitor. The thread
* releases ownership of this monitor and waits until another thread
* notifies threads waiting on this object's monitor to wake up
* either through a call to the {@code notify} method or the
* {@code notifyAll} method. The thread then waits until it can
* re-obtain ownership of the monitor and resumes execution.
* <p>
* As in the one argument version, interrupts and spurious wakeups are
* possible, and this method should always be used in a loop:
* <pre>
* synchronized (obj) {
* while (<condition does not hold>)
* obj.wait();
* ... // Perform action appropriate to condition
* }
* </pre>
* This method should only be called by a thread that is the owner
* of this object's monitor. See the {@code notify} method for a
* description of the ways in which a thread can become the owner of
* a monitor.
*
* @throws IllegalMonitorStateException if the current thread is not
* the owner of the object's monitor.
* @throws InterruptedException if any thread interrupted the
* current thread before or while the current thread
* was waiting for a notification. The <i>interrupted
* status</i> of the current thread is cleared when
* this exception is thrown.
* @see java.lang.Object#notify()
* @see java.lang.Object#notifyAll()
*/
public final void wait() throws InterruptedException {
wait(0);
}
为了避免上例中表现出的虚假唤醒(spurious wakeups),synchronized(obj)中的wait前的if判断条件,应当总是被放在while循环中。
import java.util.concurrent.TimeUnit;
/**
* 生产者、消费者写法一:synchronized
*/
public class BankcardTest4 {
Bankcard bankcard = new Bankcard();
Parent parent = new Parent(bankcard);
Son son = new Son(bankcard);
public void run1(){
for (int k = 0; k < 20; k++) {
try {
parent.deposit(1);
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void run2(){
for (int k = 0; k < 20; k++) {
try {
son.withdraw(1);
//TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
BankcardTest4 bankcardTest4 = new BankcardTest4();
new Thread(bankcardTest4::run1,"父母线程1").start();
new Thread(bankcardTest4::run1,"父母线程2").start();
new Thread(bankcardTest4::run2,"学生线程1").start();
new Thread(bankcardTest4::run2,"学生线程2").start();
}
}
class Bankcard{
private int money;
/**
* 往银行卡存钱
* @param money
*/
public synchronized void deposit(int money) throws InterruptedException {
//if (this.money >= 5){
while(this.money >=5){
System.out.println("余额已经超出5,暂不继续存钱");
this.wait();
}
this.money += money;
System.out.println(Thread.currentThread().getName() + "存入" + money + ",还剩" + this.money);
this.notifyAll();
}
/**
* 从银行卡取钱
* @param money
*/
public synchronized void withdraw(int money) throws InterruptedException {
//if(this.money < money){
while(this.money < money){
System.out.println(Thread.currentThread().getName() + "要取出" + money+",银行卡余额不足!");
this.wait();
}
this.money -= money;
System.out.println(Thread.currentThread().getName() + "取出" + money + "还剩" + this.money);
this.notifyAll();
}
}
class Parent{
private Bankcard bankcard;
public Parent(Bankcard bankCard){
this.bankcard = bankCard;
}
public void deposit(int money) throws InterruptedException {
this.bankcard.deposit(money);
}
}
class Son{
private Bankcard bankcard;
public Son(Bankcard bankCard){
this.bankcard = bankCard;
}
public void withdraw(int money) throws InterruptedException {
this.bankcard.withdraw(money);
}
}
lock/condition
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* 生产者、消费者写法二:lock / condition
*/
public class BankcardTest5 {
Bankcard bankcard = new Bankcard();
Parent parent = new Parent(bankcard);
Son son = new Son(bankcard);
public void run1(){
for (int k = 0; k < 20; k++) {
try {
parent.deposit(1);
TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void run2(){
for (int k = 0; k < 20; k++) {
try {
son.withdraw(1);
//TimeUnit.MILLISECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
BankcardTest5 bankcardTes5 = new BankcardTest5();
new Thread(bankcardTes5::run1,"父母线程1").start();
new Thread(bankcardTes5::run1,"父母线程2").start();
new Thread(bankcardTes5::run2,"学生线程1").start();
new Thread(bankcardTes5::run2,"学生线程2").start();
}
}
class Bankcard{
private int money;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
/**
* 往银行卡存钱
* @param money
*/
public /*synchronized*/ void deposit(int money) throws InterruptedException {
lock.lock();
//if (this.money >= 5){
while(this.money >=5){
System.out.println("余额已经超出5,暂不继续存钱");
//this.wait();
condition.await();
}
this.money += money;
System.out.println(Thread.currentThread().getName() + "存入" + money + ",还剩" + this.money);
//this.notifyAll();
condition.signalAll();
lock.unlock();
}
/**
* 从银行卡取钱
* @param money
*/
public /*synchronized*/ void withdraw(int money) throws InterruptedException {
lock.lock();
//if(this.money < money){
while(this.money < money){
System.out.println(Thread.currentThread().getName() + "要取出" + money+",银行卡余额不足!");
//this.wait();
condition.await();
}
this.money -= money;
System.out.println(Thread.currentThread().getName() + "取出" + money + "还剩" + this.money);
//this.notifyAll();
condition.signalAll();
lock.unlock();
}
}
class Parent{
private Bankcard bankcard;
public Parent(Bankcard bankCard){
this.bankcard = bankCard;
}
public void deposit(int money) throws InterruptedException {
this.bankcard.deposit(money);
}
}
class Son{
private Bankcard bankcard;
public Son(Bankcard bankCard){
this.bankcard = bankCard;
}
public void withdraw(int money) throws InterruptedException {
this.bankcard.withdraw(money);
}
}