【Java9】异常,finally,线程创建(卖票),线程同步(卖包子),线程练习
文章目錄
- 1.錯誤和異常區別:Arrays.toString(array)
- 2.編譯和運行異常:SimpleDateFormat
- 3.處理異常:方法聲明拋出
- 4.finally關鍵字:catch相當于else if,finally相當于else,return
- 5.自定義異常:extends
- 6.練習:常見異常
- 7.線程兩種創建方式:new Thread(new Runnable() {}),extends Thread,implements Runable
- 8.賣票:原子性
- 9.線程同步:synchronized關鍵字/方法,Lock接口,ThreadLocal
- 10.賣包子:wait,notify
- 11.在子線程中輸出1-100之間的偶數,主線程輸出1-100之間的奇數
- 12.創建和啟動2個子線程:一個打印1-10之間奇數,一個打印1-10之間偶數
- 13.創建和啟動2個子線程:一個打印奇數,一個打印偶數
- 14.使用兩個線程循環打印出1~100
- 15.使用三個線程循環打印出1~100
- 16.賬戶類:synchronized 方法
- 17.模擬多個人通過一個山洞:synchronized 方法
1.錯誤和異常區別:Arrays.toString(array)
package com.itheima01.throwable; import java.util.Arrays; //錯誤(Error) : 從程序角度 只能避開,不能解決。 異常(Exception) : 從程序角度 可以解決的問題 public class ThrowableDemo {public static void main(String[] args) { // int[] array = new int[3];//System.out.println(array); //[I@6d6f6e28//System.out.println(array.toString()); //[I@6d6f6e28//System.out.println(Arrays.toString(array)); //[0, 0, 0] // int[] array = new int[2_000_000_000]; //20億撐不住,內存條不夠 // System.out.println(Arrays.toString(array)); //java.lang.OutOfMemoryError: Java heap(堆) space //OOM :內存溢出【錯誤】int[] array = {};System.out.println(array[1]); //java.lang.ArrayIndexOutOfBoundsException【異?!?/span>} } package com.itheima02.jvm; import java.util.ArrayList; /* * throw 關鍵字(全小寫): 1. 效果等同于return,后續代碼不再執行 * 2. throw + Throwable對象(只能跟異常對象); return 返回值; * 3. 運用: 我們一般不使用, JDK方法的設計者使用 (拋出異常: api設計者 和 使用者交流方式) */ public class ThrowDemo {public static void main(String[] args) { // new ArrayList<String>(-1); //IllegalArgumentExceptionint[] array = {0,1};int element = getElement(array);System.out.println(element);}private static int getElement(int[] array) {int index = 2;if(index > array.length - 1){ //>2-1//訪問了數組不存在的索引 // ArrayIndexOutOfBoundsException e = new ArrayIndexOutOfBoundsException("you are a stupid bird,you access a wrong index:" + index); // throw e; //拋出異常,下面代碼不會執行。拋出去之后也沒人處理 throw new ArrayIndexOutOfBoundsException(index); //這一行等同上兩行 //throw new Throwable(""); //也可以,因為是編譯異常,聲明getElement方法后要加throws Throwable}int element = array[index]; //上面有throw,這里兩行都不執行return element;} }2.編譯和運行異常:SimpleDateFormat
public class ExceptionDemo {public static void main(String[] args) throws IOException {String str = "1996-01-01";SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");System.out.println(sdf); //java.text.SimpleDateFormat@f67a0200// sdf.parse(str); //解析異常ParseException也叫編譯異常,和IOException并列關系,main聲明需拋出。Date parse = sdf.parse(str); //加上Date parse不報錯System.out.println(parse); //Mon Jan 01 00:00:00 CST 1996// FileOutputStream fos = new FileOutputStream(""); //FileNotFoundException是IOException子類 // fos.write(97); //IOException是最經典的編譯異常//111111111111111111111111111111111111111111111以下都為RuntimeException的子類 // 1. NullPointerException 空指針String s = null; // System.out.println(s.length());// 2. IndexOutOfBoundsException 索引越界int[] array = {}; // System.out.println(array[1]);// 3. ClassCastException 類轉換// 4. IllegalArgumentException 非法參數new ArrayList<String>(-1);} }3.處理異常:方法聲明拋出
package com.itheima03.throwsd; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException;public class ThrowsDemo {public static void main(String[] args) throws IOException {method01(); //表哥又拋出去叫大哥(jvm,因為main方法調用者是jvm),jvm出錯又打印終止} /** throws 關鍵字* 1. 用在方法聲明上: 修飾符 返回值類型 方法名(參數列表) throws 異常類型(A)* 2. 這是處理異常的一種方式: 聲明將異常拋出給調用者處理(假手與人)* 3. 注意: 這里的異常類型A 必須跟方法里要拋出的異常B一致, 或者A是B的父類 (向上轉型)* * 語法: throws 異常1,異常2{ }* 運用: 我們可以在某一方法的設計上先聲明拋出異常,可以方法的調用處進行處理* 切記有有一環節必須處理, 不然到JVM中, 出現異常就崩潰。如果明知不會錯的異常,直接throws。*/private static void method01() throws IOException { //交給表哥 FileOutputStream fos = new FileOutputStream("a.txt");fos.write(97);} } package com.itheima04.trycatch;public class TrycatchDemo {public static void main(String[] args) {int[] array = {0,1};try{int element = array[2];System.out.println(element);}catch (Exception e){//catch關鍵字監視try中代碼塊,我們程序自己把異常處理了,所以不會傳給JVM,程序不會終止。e.printStackTrace();//打印異常信息: 打印棧中追溯,案發地點在方法棧中。jvm不會打印了,我們自己手動打印。這行注釋了,下面紅字不會打印,但“出現異常..繼續運行...”都會打印出。System.out.println("出現異常,并被捕獲了");}System.out.println("程序繼續執行");} } package com.itheima04.trycatch; import java.util.Scanner; /* * try...catch運用: 1. 如果代碼都是由我們自己編寫的,我們一般都不會出現異常 * 2. 有些代碼需要用戶參與編寫 (交互: 我們程序輸出,用戶輸入) *思想: 我們預知代碼可能運行結果(如果了包含了異常, 提前try...cath并給出提示或者解決方案) */ public class TryCatchDemo02 {public static void main(String[] args) {Scanner sc = new Scanner(System.in);System.out.println("請輸入一個被除數:");int a = sc.nextInt(); System.out.println("請輸入一個除數:");int b = sc.nextInt(); try { int result = a/b; //java.lang.ArithmeticException: / by zero 算術異常System.out.println(result);}catch (Exception e){System.out.println("你個傻鳥,除數不能為0");}System.out.println("軟件繼續讓你玩");} } package com.itheima04.trycatch; /*try{}catch (NullPointerException e){//1. 如果出現了空指針,應該提示...}catch (IndexOutOfBoundsException e2){//2. 如果出現了索引越界, 應該提示...}執行順序:如果try中代碼發生異常, 那么多個catch會從上到下逐一嘗試捕獲, 如果被A捕獲了,后續的catch不再執行。 注意: 1. 前面catch中的異常類型不能是后面catch中的異常類型的父類或者相同 (因為這樣的話,后續catch執行不到沒有意義) 2. 后面catch中的異常類型可以是前面的父類。 */ public class TryCatchCatchDemo {public static void main(String[] args) {try{method01(2);}catch (NullPointerException e){System.out.println("發生了空指針異常");}catch (IndexOutOfBoundsException e2){System.out.println("發生了索引越界異常");}System.out.println("代碼繼續執行");}//模擬: 這段代碼可能有兩個異常(一段代碼里面不論可能有多少個異常,一次運行最多拋出一個異常)private static void method01(int a) {if(a == 1){throw new NullPointerException("空指針"); //throw天生與其他代碼互斥,一旦發生throw,其他代碼不再運行}else if(a == 2){throw new IndexOutOfBoundsException("越界異常");}else{System.out.println("什么事都沒發生");}} }4.finally關鍵字:catch相當于else if,finally相當于else,return
package com.itheima04.trycatch; /*try{}catch (Exception e){}finally {// 無論如何,一定最后執行。 作用: (IO流)釋放資源} */ public class FinallyDemo {public static void main(String[] args) { // method();int number = method2(); //運行 :3System.out.println(number); //1} //111111111111111111111111111111111111111111111111111111111111111111111 private static int method2() {int i = 1;try{ // System.exit(0); //拔電源阻止finallyreturn i; //一般return后續代碼不會執行了,但finally會搶奪try...catch中的return執行權,finally會先執行,執行完又回到return //return 安全機制: 把i的值給記錄下來了1 ,所以return 1 }catch (Exception e){ //沒有異常,i永遠不會=2i = 2;}finally {i = 3;System.out.println("運行 :" + i);}return i; //不執行,因為try catch finally有return了}//11111111111111111111111111111111111111111111111111111111111111111111private static void method() {try{int i = 4/0;System.out.println(i);}catch (NullPointerException e){System.out.println("異常發生了");}finally {System.out.println("無論如何一定執行");}System.out.println("程序繼續執行");} }
5.自定義異常:extends
package com.itheima05.custom; /* * JavaBean : 標準類 (封裝) * 1. private屬性 * 2. public get set方法 * 3. public 空參構造,不聲明構造會有一個空參構造。 寫滿參構造就得寫空參構造。 * 封裝: 1. private屬性 為了不對外直接暴露 -> 安全 * 2. public get set方法【方法跟屬性最大不同, 方法可以加條件判斷(健壯性校驗)】 * 繼承: 自定義異常 */ public class Student {private String name;private int age;@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {if(age < 0){ // throw new IllegalArgumentException("你個傻鳥,age沒有負數");throw new NoAgeException("你個傻鳥,age沒有負數"); //不報錯,因為下面有定義class NoAgeException extends 。。。}this.age = age;} } package com.itheima05.custom; /* * 自定義異常: IllegalArgumentException : 非法參數異常 * NoAgeException : 非法年齡異常(框架: 很多JDK沒有的異常,自定義) */ public class CustomDemo {public static void main(String[] args) {Student s = new Student();s.setName("張三"); // s.age = -18; // 非法訪問,安全隱患,所以private int age;s.setAge(-18); //在方法里加安全機制System.out.println(s);} } class NoAgeException extends IllegalArgumentException{public NoAgeException(String msg){super(msg); //調用IllegalArgumentException,Ill..又調用自己的super。。} } package com.itheima06.notice; import java.io.IOException; /* * 現象: 1.父類 方法中聲明編譯異常【void method() throws IOException{}】,而子類沒有聲明編譯異常 不會報錯 * 2.父類 方法中未聲明編譯異常,而子類有聲明編譯異常 會報錯 !!!!! * * 解釋: 現象2 跟 多態沖突了 * 1.現象2在多態中,編譯器只看左邊,父類方法沒有編譯異常,以為沒有編譯異常,不需要處理 * 2.運行看右邊,子類重寫的方法運行時有編譯異常 (編譯異常要求編譯時期必須處理) * 沖突: 編譯異常 繞過了 編譯器 (編譯器強制報錯) */ public class NoticeDemo {public static void main(String[] args) throws IOException { Fu fu = new Zi(); //編譯看左邊,運行看右邊fu.method();} } class Fu{void method() {} } class Zi extends Fu{@Overridevoid method() throws RuntimeException{ //運行異常 不報錯 } }如下是方法重寫注意事項,編譯異常報錯。
6.練習:常見異常
package com.atguigu.test01.review; // 編寫代碼演示棧內存溢出 StackOverflowError(遞歸導致內存溢出) public class TestError1 {public static void main(String[] args) {Son s = new Son();s.test(); //自己調用自己,不調用父類test()方法。java.lang.StackOverflowError} } class Father{public void test(){System.out.println("父類的");} } class Son extends Father{public void test(){ //調用父類的test();要用super.test()test();System.out.println("子類的");} } package com.atguigu.test01.review; import java.util.ArrayList; // 請編寫代碼演示OOM:OutOfMemoryError public class TestError2 {public static void main(String[] args) {//1、答案一:創建一個超級大數組,//數組的長度的類型是int,Integer是int類型的一個包裝類,Integer.MAX_VALUE是2的31次方-1 // int[] arr = new int[Integer.MAX_VALUE]; //2、答案二:不斷的創建對象ArrayList list = new ArrayList();//容器,用來裝對象while(true){list.add(new Object());}} } public class TestFinallyNoReturn2 {public static void main(String[] args) {int num = getNum(4);System.out.println(num);//0,不是30}public static int getNum(int a){int result = 10;try{System.out.println(a/0); //直接跳到catchif(a > 0){result = 20;return result;}else if(a < 0){result = -20;return result;}else{return result;}}catch(Exception e){System.out.println("exception");result = 0;return result;}finally{result = 30;System.out.println("finally"); // return result;//如果有這句,最后一行結果就變成30}} }
7.線程兩種創建方式:new Thread(new Runnable() {}),extends Thread,implements Runable
如下FileOutputStream源碼中拋出異常,為了讓寫代碼人自己寫try catch異常提示信息。
如下線程第一種創建方式。
8.賣票:原子性
package com.itheima03.ticket; /* * 需求假設某航空公司有三個窗口發售某日某次航班的100張票,100張票可以作為共享資源,三個售票窗口需要創建三個線程 * 好處: 多線程執行同一任務,比較快。 * 1. 程序(單線程) , 并發1600線程, cpu分配執行權: 1/1600 * 2. 程序(多線程 100) , 并發1700, cpu分配給我們的程序執行權更多:1/17 * 注意: 線程不是越多越好(線程本身很占內存, 慢。票數不多不需要用多線程)。 */ public class TicketDemo01 {public static void main(String[] args) {MyWindow mw1 = new MyWindow(); //堆中開一塊空間 mw1.setName("窗口壹");MyWindow mw2 = new MyWindow(); //同上mw2.setName("窗口222");MyWindow mw3 = new MyWindow(); //同上mw3.setName("窗口三三三"); mw1.start();mw2.start();mw3.start();} }//11111111111111111111111111111111111111111111111111111111111111111111111111111 class MyWindow extends Thread{static int number = 100; //去掉static,每創建一個MyWindow窗口在堆里開辟一塊空間,三個窗口各賣100張@Overridepublic void run() {while(number > 0){System.out.println(Thread.currentThread().getName() + "正在賣出第" + number + "張票");number--;}} } /* * 兩種線程創建方式: 1.繼承Thread 2.實現Runnbale 。第二種方案會更好一些,不需要加static,因為只new了一個對象。 * 1. 實現接口,而不是繼承類(擴展性更強) 接口可以多實現,但是類只能單繼承(MyWindow繼承Thread后,就不能繼承另外的類。MyTask可以繼承其他類,實現其他接口) * 2. 更符合 面向對象 (高內聚,低耦合:線程獨立,和業務代碼MyTask分離,傳入賣豬肉任務也行)。封裝(各干各的,有必要再進行合作) */如下線程同步問題分析:兩種創建方式3個窗口都總賣出102張票,而不是100張。原因:三個窗口同時卡在打印正在賣出第100張票。解決:t1在賣第100張票時,cpu可能會切到t3和t2,可以控制t2和t3不動,等t1的number- -完再動。
9.線程同步:synchronized關鍵字/方法,Lock接口,ThreadLocal
package com.itheima04.synchronizedd; import java.io.IOException; /* * 1. 代碼塊 * synchronized(鎖對象){ * 代碼A * } * 1. 鎖對象可以是任意對象,但必須唯一 * 2. 同步代碼塊中的 代碼A 同一時間,只允許一個線程執行 * * 使用同步鎖的注意點:1. 在保證業務邏輯可用的情況,同步鎖加的范圍越小越好 * 2. 鎖對象必須唯一: * <1> 如果能保證當前對象唯一,this也可以作為鎖對象 (更節省內存) * <2> 當前類名.class(最好的鎖對象) -> Class對象(一個類被加載,在內存都會有一個Class對象) 反射 */ public class TicketDemo02 {public static void main(String[] args) {MyTask mt = new MyTask(); //只new了一個,可以用this Thread t1 = new Thread(mt);t1.setName("窗口壹");Thread t2 = new Thread(mt);t2.setName("窗口222");Thread t3 = new Thread(mt);t3.setName("窗口三三三"); t1.start();t2.start();t3.start();} }class MyTask implements Runnable{ int number = 100; // Object obj = new Object(); //鎖對象@Overridepublic void run() {while(number > 0){//1111111111111111111111111111111111111111111111111111111111111111111111111111111111111 synchronized(MyTask.class){ //MyTask.class也可以換成thisif(number <= 0){break; //跳出while大循環}System.out.println(Thread.currentThread().getName() + "正在賣出第" + number + "張票");number--;} //111111111111111111111111111111111111111111111111111111111111111111111111111111111111 //這邊只能try catch不能throws,原因:父類Runnable中run方法沒有聲明拋出編譯異常,所以子類也不能throws try {Thread.sleep(1); //線程啥事也不干,暫停1ms,cpu有空閑切換其他線程} catch (InterruptedException e) { //這異常一般發生在線程中,當一個正在執行的線程被中斷時就會出現這個異常e.printStackTrace();}} //while里} }
如下t2賣到0張時出while,而t1和t3還在while里,此時number=0,所以變為0和-1。
如下把synchronized拖到外面也不行。
如下加if(number <= 0),沒有加浪費時間代碼,所以看不到交替效果,但不會出現0和-1。
obj是鎖對象即鑰匙,如下鑰匙不能進run方法(每個線程一把即三把鑰匙了),只能在成員位置。
用this,不用new object(),可以節約內存。
如下t1和t2兩個線程隔離。
t1(…,User),每次傳User對象顯得麻煩。如下可將User放入ThreadLocal中,每次在每個函數中通過ThreadLocal.get拿到線程的User。
如下一個請求過來的生命周期是先要經過過濾器/攔截器再到servlet,才會有后續的視圖等,這是springmvc的一個生命周期。
如下可看出在MyFilter中設置了ThreadLocal相當于設置了整條請求(經過filter - servlet - 攔截器等等),一條路上整個都會有上下文,在當前線程的上下文拿到這個值。
每個線程都是有ThreadLocal上下文的,線程執行完后并沒有銷毀,原因是springmvc用的是線程池,這個線程池線程對象并沒有銷毀,下一次給其他請求再去使用,再去使用時這個線程里的ThreadLocal其實是上一次即線程前世所設置的值,所以當前ThreadLocal用完后要清理掉。
ThreadLocal(線程本地)設為的是一個全局變量,為什么在不同線程中get和set能隔離?ThreadLocal本身不存儲任何值,如下的value就是t.get和set的值
10.賣包子:wait,notify
package com.itheima07.bz;public class Demo {public static void main(String[] args) throws InterruptedException {Object obj = new Object(); // obj.wait(); //IllegalMonitorStateException : 非法的監視狀態異常,因為.wait()必須鎖對象調用如下synchronized (obj){ //對象變成鎖對象obj.wait(); //不會報錯,一直等待。在鎖對象中}} }如下兩個方法wait和notify不是給線程調用的,而是給鎖對象【鎖對象可以是任意對象】調用的如上所示。BaoZi只能一個線程對其操作。
如下第一次沒有包子,所以繞過2中if到1。運行完1后就有包子了,1時間很短,cpu不切換線程,切換了也沒用,因為2中syn…(bz)包子被鎖住,就算切換到吃貨線程進不去syn…(bz)里,所以1中notify喚不醒吃貨線程。
1和2都在sy…(bz)里,bzp線程bz.wait()【有3個好處】進入等待狀態即進入監視隊列即等待包子被吃,吃貨線程的synchronized鎖被打開,有包子不會wait,執行3。
一個線程wait把自己停下來放入堆(監視隊列)中,來年開春,另一個線程中3叫我起來干活。2和3對應,1和4對應。3喚醒了2中wait,但2沒鑰匙(鎖)動不了(鬼壓床),鑰匙在吃貨手上,所以3往后4執行釋放鎖,1234不停循環執行。
生產消費者模型:用戶發請求來相當于包子鋪生產包子即生產者。服務器24小時開著相當于消費者一天24小時等包子吃。不會讓消費者線程空轉浪費cpu資源,所以沒包子設置消費者線程為wait狀態不占用cpu資源。
如下一直交替運行,不停。
如下線程6態:鎖就是鑰匙上廁所,限時等待就是sleep,記住blocked,waitting,runnable。
如下B進不去不執行。
11.在子線程中輸出1-100之間的偶數,主線程輸出1-100之間的奇數
package com.atguigu.test02.homework01;public class Test01 {public static void main(String[] args) {new Thread(){public void run(){for (int i = 0; i <= 100; i+=2) {System.out.println("子線程:" + i);}}}.start(); for (int i = 1; i <= 100; i+=2) {System.out.println("主線程:" + i);}} }12.創建和啟動2個子線程:一個打印1-10之間奇數,一個打印1-10之間偶數
package com.atguigu.test03.homework02; //(1)要求每個線程要么不打印,要么就連續打印5個數,每個數打印間隔500毫秒 。(2)但兩個線程不要求交替打印。 public class Test02 {public static void main(String[] args) {Odd o = new Odd();Even e = new Even(); o.start();e.start();} }class Odd extends Thread{private int num = 1;public void run(){while(true){synchronized (Thread.class) {for (int i = 1; i <=5; i++) {System.out.println("奇數線程,第" + i + "個:" + num);num += 2;try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}} }} }class Even extends Thread{private int num = 0;public void run(){while(true){synchronized (Thread.class) {for (int i = 1; i<=5; i++) {System.out.println("偶數線程,第" + i + "個:" + num);num += 2;try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}}}}} }13.創建和啟動2個子線程:一個打印奇數,一個打印偶數
package com.atguigu.test05.homework03.copy; //(1)要求實現交替打印。(2)每個數打印間隔1秒 public class Test03 {public static void main(String[] args) {MyThread t1 = new MyThread();MyThread t2 = new MyThread(); t1.start();t2.start();} }class PrintNumber{private static int num = 1; public static synchronized void print(){try {PrintNumber.class.notify();System.out.println(Thread.currentThread().getName() + ":" + num);num++;PrintNumber.class.wait();} catch (InterruptedException e) {e.printStackTrace();}} }class MyThread extends Thread{public void run(){while(true){PrintNumber.print(); //靜態方法try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}} }14.使用兩個線程循環打印出1~100
package com.itheima.demo01;class Num {int i;boolean falg; }class TestThread1 {public static void main(String[] args) {Num num=new Num();Thread t1=new Thread(new A(num));Thread t2=new Thread(new B(num));t1.start();t2.start();} }//1111111111111111111111111111111111111111111111111111111111111111111111 class A implements Runnable{private Num num;public A(Num num) {this.num=num;}@Overridepublic void run() {while(num.i<99){synchronized(num){//1111111111111111111111111111111111111111111111111111111111111111111if(num.falg){try {num.wait();} catch (InterruptedException e) {}}num.i++;num.falg=true;System.out.println(Thread.currentThread().getName()+"-"+num.i);num.notify();}}} }//1111111111111111111111111111111111111111111111111111111111111111111111 class B implements Runnable{private Num num;B(Num num){this.num=num;}@Overridepublic void run() {while(num.i<99){synchronized(num){//11111111111111111111111111111111111111111111111111111111111111111if(!num.falg){try {num.wait();} catch (InterruptedException e) {}}num.i++;num.falg=false;System.out.println(Thread.currentThread().getName()+"-"+num.i);num.notify();}}} }15.使用三個線程循環打印出1~100
package com.itheima.demo01;class TestThread2 {public static void main(String[] args) throws Exception{Thread t1 = new Thread(new MyThread1(0));Thread t2 = new Thread(new MyThread1(1));Thread t3 = new Thread(new MyThread1(2));t1.start();t2.start();t3.start();}static class MyThread1 implements Runnable {private static Object lock = new Object();private static int count = 0;int no;public MyThread1(int no) {this.no = no;}@Overridepublic void run() {while (true) {synchronized (lock) {//11111111111111111111111111111111111111111111111111111111111111111111if (count >= 100) {break;}if (count % 3 == this.no) {count++;System.out.println(this.no + "--->" + count);} else {try {lock.wait();} catch (InterruptedException e) {e.printStackTrace();}}lock.notifyAll();}}}} }16.賬戶類:synchronized 方法
package com.atguigu.test06.homework04; /*案例:1、創建一個銀行賬戶類:(1)屬性:賬號,余額。(2)get/set。(3)toString():返回:賬戶:xxx,余額:xxx2、創建一個丈夫類:負責往里存錢,每次存款[0,10000)以內不等3、創建一個妻子類:負責取錢,每次取款[0,10000)以內不等,如果余額不足,要等丈夫存夠了才能取 */ public class Test04 {public static void main(String[] args) {Account a = new Account("1122", 0);AccountManager am = new AccountManager(a);Husband h = new Husband("崔志恒",am);Wife w = new Wife("甄玉祿",am); h.start();w.start();} }//1.11111111111111111111111111111111111111111111111111111111111111111111111 class Husband extends Thread{private AccountManager am;public Husband(String name,AccountManager am) {super(name);this.am = am;}public void run(){while(true){am.save();try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}}} }//2.11111111111111111111111111111111111111111111111111111111111111111111111 class Wife extends Thread{private AccountManager am;public Wife(String name,AccountManager am) {super(name);this.am = am;}public void run(){while(true){am.withdraw();try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}}} }//3.11111111111111111111111111111111111111111111111111111111111111111111111 class AccountManager{private Account account; public AccountManager(Account account) {super();this.account = account;} public synchronized void save(){double money = Math.random() * 10000;System.out.println(Thread.currentThread().getName() + "開始存錢,目前賬戶狀態:" + account); //自動調用account.tostring方法System.out.println("本次存錢的數量是:" + money);account.setBalance(account.getBalance() + money);System.out.println(Thread.currentThread().getName() + "存錢結束,目前賬戶狀態: " + account);this.notify();} public synchronized void withdraw(){double money = Math.random() * 10000;System.out.println(Thread.currentThread().getName() + "開始取錢,目前賬戶狀態:" + account);while(money > account.getBalance()){try {System.out.println("本次想取錢的數量是:" + money + ",余額不足....");this.wait();} catch (InterruptedException e) {e.printStackTrace();}}account.setBalance(account.getBalance() - money);System.out.println(Thread.currentThread().getName() + "取錢結束,目前賬戶狀態: " + account);} }//4.111111111111111111111111111111111111111111111111111111111111111111111111 class Account{private String id;private double balance;public Account(String id, double balance) {super();this.id = id;this.balance = balance;}public Account() {super();}public String getId() {return id;}public void setId(String id) {this.id = id;}public double getBalance() {return balance;}public void setBalance(double balance) {this.balance = balance;}@Overridepublic String toString() { return "賬戶: " + id +"余額:" + balance; //賬戶:xxx,余額:xxx} }17.模擬多個人通過一個山洞:synchronized 方法
package com.atguigu.test07.homework05; /* ? 1、這個山洞每次只能通過一個人,每個人通過山洞的時間為5秒; ? 2、隨機生成10個人,同時準備過此山洞 ? 3、定義一個變量用于記錄通過隧道的人數 ? 4、顯示每次通過山洞人的姓名,和通過順序;*/ public class Test05 {public static void main(String[] args) {Tunnel t = new Tunnel(); for (int i = 1; i <= 10; i++) {Thread th = new Thread(t, "p" + i);th.start();}} }//111111111111111111111111111111111111111111111111111111111111111111111111111 class Tunnel implements Runnable{private int num; public void run(){cross();} public synchronized void cross(){ //每次只能由一個線程執行,相當于是一個人通過System.out.println(Thread.currentThread().getName() + "準備開始通過...");try {Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}num++;System.out.println(Thread.currentThread().getName()+"通過了隧道,TA是第" + num);} }
總結
以上是生活随笔為你收集整理的【Java9】异常,finally,线程创建(卖票),线程同步(卖包子),线程练习的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Java8】堆栈/队列/数组/链表/红
- 下一篇: 【Java10】lambda表达式(函数