【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【异常】} } 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表达式(函数