题目:
完善如下程序:下列程序模拟了父亲与儿子操作同一账户,儿子每次从账户上取钱时判断账户余额,如果小于 300,则等待,否则取走 300 元,并通知父亲存钱;父亲每次往账户上存入时判断账户余额,当账户余额大于等于 300 元时,则等待,否则存入 1000 元并通知儿子取钱。
-
public class Acount { private int money = 1000; public synchronized void save() {//父亲存钱 //完善该方法 } public synchronized void take() {//儿子取钱 //完善该方法 } } public class Bank implements Runnable { private Acount acount; private Thread son,father; public Bank(){ acount=new Acount(); son=new Thread(this,"儿子"); father=new Thread(this,"父亲"); } @Override public void run() { while(true){ if(Thread.currentThread()==son){ acount.take(); }else if(Thread.currentThread()==father){ acount.save(); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String[] args) { Bank bank=new Bank(); bank.son.start(); bank.father.start(); } }
从中我们可以知道,它的意思是让我们实现线程的同步及协调运行的目的,而我们要实现这个目标,则要知道以下几个知识点。
我们先来看一下关键词——synchronized
synchronized,Java 语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这个段代码。当两个并发线程访问同一个对象 object 中的这个加锁同步代码块时,一个时间内只能有一个线程得到执行。另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。然而,当一个线程访问 object 的一个加锁代码块时,另一个线程仍然可以访问该 object 中的非加锁代码块。
synchronized 关键字,代表这个方法加锁,相当于不管哪一个线程(例如线程 A),运行到这个方法时,都要检查有没有其它线程 B(或者 C、 D 等)正在用这个方法(或者该类的其他同步方法),有的话要等正在使用 synchronized 方法的线程 B(或者 C 、D)运行完这个方法后再运行此线程 A,没有的话,锁定调用者,然后直接运行。它包括两种用法:synchronized 方法和 synchronized 块。
synchronized 方法
1.方法声明时使用,放在范围操作符(public 等)之后,返回类型声明(void 等)之前.这时,线程获得的是成员锁,即一次只能有一个线程进入该方法,其他线程要想在此时调用该方法,只能排队等候,当前线程(就是在 synchronized 方法内部的线程)执行完该方法后,别的线程才能进入.
例如:
public synchronized void run(){ //方法体 }
如在线程 t1 中有语句 obj.run() ; 那么由于 run 被 synchronized 修饰,在执行该语句前, 需要先获得调用者 obj 的对象锁, 如果其他线程 (如 t2) 已经锁定了 obj (可能是通过 obj.run ,也可能是通过其他被 synchronized 修饰的方法 obj.otherSynMethod 锁定的 obj), t1 需要等待直到其他线程 (t2) 释放 obj , 然后 t1 锁定 obj, 执行 run 方法. 返回之前之前释放 obj 锁.
2.对某一代码块使用,synchronized 后跟括号,括号里是变量,这样,一次只有一个线程进入该代码块.此时,线程获得的是成员锁.
例如:
public Object synMethod(Object a1){ synchronized(a1){ //一次只能有一个线程进入 } }
我们就先说它的这两个用处,下边我们来解一下这道题。
首先根据题目中的代码,我们可以确定它需要写在两个不同的 java 类中,好的,那我们就分装开写。
一个叫做Bank,一个叫做Acount
根据题目中的明显的提示,我们知道,实际上他给的就是一个完整的代码,而我们要做的就是填空
我们只需要将Acount中的存取关系填入即可,另外,代码中已经加入了我们需要学习的关键词,所以我们也不需要再写它了,但是我们在填空的过程中应该学习一下题目中关键字的用法。
Acount类中填入代码后,完整的块应该是
父亲存钱方法
public synchronized void save() {//父亲存钱 //完善该方法 if (money>=300) { try { wait(2000); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } else{ money+=1000; System.out.println("爸爸打电话给儿子,说:"+"儿子啊,你老爸我刚给你存了 1000 元,想去就取哦。卡上还有"+money+"元");//用于了解卡内金额变化情况 } }
儿子取钱方法
public synchronized void take() {//儿子取钱 //完善该方法 if (money<300) { System.out.println("儿子打电话给爸爸,说:"+"爸啊,我卡上没钱了,你能给我存钱吗?卡上还有"+money+"元"); } else{ money-=300; System.out.println("儿子打电话给爸爸,说:"+"爸啊,我刚取了 300 元");//用于了解卡内金额变化情况 try { wait(1000); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } }
Bank 类中,则将题目中 Bank 类的代码添加进去,如此形成两个类,我们在运行时,运行含有 Main 方法的 Bank 类,我们则可以在控制台上看到运行的结果。
儿子打电话给爸爸,说:爸啊,我刚取了 300 元儿子打电话给爸爸,说:爸啊,我刚取了 300 元儿子打电话给爸爸,说:爸啊,我刚取了 300 元爸爸打电话给儿子,说:儿子啊,你老爸我刚给你存了 1000 元,想去就取哦。卡上还有 1100 元儿子打电话给爸爸,说:爸啊,我刚取了 300 元儿子打电话给爸爸,说:爸啊,我刚取了 300 元儿子打电话给爸爸,说:爸啊,我刚取了 300 元儿子打电话给爸爸,说:爸啊,我卡上没钱了,你能给我存钱吗?卡上还有 200 元
整个 Java 项目的下载,在文章的右下角,可以点击下载哦!
文件项目下载:点击下载
转载请注明:转自 © TeenShare 梯云分享