Java基础8-多线程;同步代码块
作业解析
-
利用白富美接口案例,土豪征婚使用匿名内部类对象实现。
interface White{ public void white(); } interface Rich{ public void rich(); } interface Beauty{ public void beauty(); } interface WRB extends White, Rich, Beauty{ } class TuHao{ public void getMarry(WRB wrb){ wrb.white(); wrb.rich(); wrb.beauty(); } } class Demo{ public static void main(String[] args){ TuHao wsc = new TuHao(); wsc.getMarry(new WRB(){ public void white(){ System.out.println("white"); } public void rich(){ System.out.println("rich"); } public void beauty(){ System.out.println("beauty"); } }); } }
-
定义三角形类Trianle,里面包含三个int类型属性,分别表示三条边的长度,
构造三角形对象时,任意两边之和是否大于第三边,如若不成立,抛出自定义异常。class Triangle{ private int a; private int b; private int c; public Triangle(int a, int b, int c){ try{ if(a>=b+c || b>=a+c || c>=a+b){ throw new TriangleLengthException("Invalid Length"); } else{ this.a = a; this.b = b; this.c = c; } } catch(TriangleLengthException e){ e.printStackTrace(); } } } class TriangleLengthException extends Exception{ String exceptionInfo; public TriangleLengthException(String info){ exceptionInfo = info; } public void printStackTrace(){ System.out.println(exceptionInfo); } } class TriExceptionDemo{ public static void main(String[] args){ Triangle t1 = new Triangle(2,3,4); Triangle t2 = new Triangle(2,2,4); Triangle t3 = new Triangle(2,7,4); } }
-
Person类中增加birthday属性,对setBirthday(int ,int , int )方法进行异常处理,
要求年有效、月有效、日有效、年月日指定的具体日期有效,对不同情况分别抛出不同的异常。
year:>1970, month:1-12, day:1-31class Person{ private int year; private int month; private int day; public void setBirthday(int year, int month, int day){ try{ if(year<1970){ throw new YearException("Invalid Year"); } else{ if(month<1 || month > 12){ throw new MonthException("Invalid Month"); } else{ if(day<1 || day>31){ throw new DayException("Invalid Day"); } else{ switch(month){ case 1: case 3: case 5: case 7: case 8: case 10: case 12: break; case 2: if((year%400==0) || (year%4==0 && year%100!=0)){ if(day>29){ throw new DateException("Invalid Date"); } } else{ if(day>28){ throw new DateException("Invalid Date"); } } case 4: case 6: case 9: case 11: if(day==31){ throw new DateException("Invalid Date"); } } } } } } catch(Exception e){ e.printStackTrace(); } } } class YearException extends Exception{ String exceptionInfo; public YearException(String info){ exceptionInfo = info; } public void printStackTrace(){ System.out.println(exceptionInfo); } } class MonthException extends Exception{ String exceptionInfo; public MonthException(String info){ exceptionInfo = info; } public void printStackTrace(){ System.out.println(exceptionInfo); } } class DayException extends Exception{ String exceptionInfo; public DayException(String info){ exceptionInfo = info; } public void printStackTrace(){ System.out.println(exceptionInfo); } } class DateException extends Exception{ String exceptionInfo; public DateException(String info){ exceptionInfo = info; } public void printStackTrace(){ System.out.println(exceptionInfo); } } class BirthdayExceptionDemo{ public static void main(String[] args){ Person p1 = new Person(); p1.setBirthday(12,1,22); p1.setBirthday(1970,13,22); p1.setBirthday(2000,1,32); p1.setBirthday(2000,2,28); p1.setBirthday(2000,2,29); p1.setBirthday(2016,2,30); p1.setBirthday(2100,2,29); } }
-
将类定义到指定的包下。com.xkzhai.jar,编译之后,打成jar文件。
-
编写源文件jarDemo.java
package com.xkzhai.jar; class Person{ private String name; private String sex; public void run(){ System.out.println("run"); } } class jarDemo{ public static void main(String[] args){ Person p1 = new Person(); p1.run(); } }
-
编译到指定的位置
javac -d classes2 jarDemo.java
-
归档
jar cvf test.jar -C classes2/ . jar cvfe test2.jar com.xkzhai.jar.jarDemo -C classes2/ . //在清单文件中增加入口点
-
运行程序
java -cp classes2 com.xkzhai.jar.jarDemo java -cp test.jar com.xkzhai.jar.jarDemo java -jar test2.jar//定义好入口点的jar包
-
-
相互之间使用jar包,放置cp下,对class进行重用
-
编写第一个java程序Person.java
package com.xkzhai.jar1; //不同包下的类重用,需定义为public public class Person{ private String name; private String sex; private int age; public void setAge(int age){ this.age = age; } public int getAge(){ return age; } }
-
编译上述文件,放置到classes3文件夹下
javac -d classes3 Person.java
-
将类文件打包归档为jar1.jar,放置在lib文件夹下
jar cvf jar1.jar -C classes3/ .
-
重用Person类,编写第二个java程序jarDemo2.java,放置在src文件夹下
package cn.xkzhai; import com.xkzhai.jar1.Person; class Student extends Person{ private String ID; } class jarDemo2{ public static void main(String[] args){ Student s1 = new Student(); s1.setAge(20); System.out.println(s1.getAge()); } }
-
编译jarDemo2.java,生成的类文件放置在classes中
javac -cp lib/jar1.jar -d classes src/jarDemo2.java
-
执行
java -cp lib/jar1.jar;classes cn.xkzhai.jarDemo2
-
-
设计程序,考查修饰符。public -> protected -> default -> private(选做题)
-
编写ArrayTool,把冒泡排序,选择排序,二分法查找等打成jar包。
-
编写java源文件ArrayTool3.java
package com.xkzhai.array; class ArrayTool3{ int[] arrayData; public ArrayTool3(){ } public ArrayTool3(int[] arrayData){ this.arrayData = arrayData; } //1. 打印数组元素 public void outArray(){ for(int i: arrayData){ System.out.println(i); } } //2. 冒泡排序 // 5 4 3 2 1 // 4 3 2 1 5 // 3 2 1 4 5 // 2 1 3 4 5 // 1 2 3 4 5 public void bubbleSort(){ for(int i = arrayData.length-1;i>0;i--){ for(int j=0;j<i;j++){ if(arrayData[j]>=arrayData[j+1]){ int tmp = arrayData[j]; arrayData[j] = arrayData[j+1]; arrayData[j+1] = tmp; } } } } //3. 选择排序 //5 4 3 2 1 //1 5 4 3 2 //1 2 5 4 3 //1 2 3 5 4 //1 2 3 4 5 public void selectSort(){ for(int i=0;i<arrayData.length-1;i++){ for(int j=i;j<=arrayData.length-1;j++){ if(arrayData[j]<=arrayData[i]){ int tmp = arrayData[j]; arrayData[j] = arrayData[i]; arrayData[i] = tmp; } } } } //4. 选择排序 public int halfFind(int c){ int min = 0; int max = arrayData.length-1; int index = 0; while(min<=max){ index = (min+max)/2; if(arrayData[index]>c){ max = index-1; } else if(arrayData[index]<c){ min = index+1; } else{ return index; } } return -1; } } class ArrayDemo{ public static void main(String[] args){ ArrayTool3 arr = new ArrayTool3(new int[]{1,3,2,20,12}); arr.outArray(); arr.bubbleSort(); arr.outArray(); ArrayTool3 arr2 = new ArrayTool3(new int[]{1,3,2,20,12,23,21,19}); arr2.outArray(); arr2.selectSort(); arr2.outArray(); System.out.println(arr2.halfFind(-1)); System.out.println(arr2.halfFind(12)); } }
-
编译,打包
javac -d classes4 ArrayTool3.java //java -cp classes4 com.xkzhai.array.ArrayDemo jar cvf ArrayTool.jar -C classes4/ .
-
-
预习多线程。
进程
-
运行时(runtime)的应用程序
-
进程之间的内存不是共享(独占)
-
进程间通信使用的socket(套接字)
进程之间内存是隔离的。内存不共享。
多线程
-
程序(进程)执行过程中,并发执行的代码段
-
线程之间共享内存
-
创建灵活响应的桌面程序
-
每个运行着的线程对应一个stack(方法栈)
-
应用程序至少有一个线程(主线程)
java.lang.Thread
-
Thread.yield()方法:让当前线程让出CPU抢占权,具有谦逊之意,瞬时的动作
-
Thread.sleep(int mils)方法:让当前线程休眠指定毫秒数,放弃cpu抢占权,和锁旗标(监控权)没有关系
-
Thread.join():当前线程等待指定的线程结束后才能继续运行
-
daemon:守护线程,服务员 Thread.setDaemon(true),为其他线程提供服务的线程。若进程中剩余的线程都是守护线程的话,则进程终止了。
-
\(--\) 原子性操作
-
线程间通信,共享资源的问题。锁, 将并行转串行,防止并发访问。参照物,锁旗标
//同步代码块 synchronized(object lock){ ... }
同步代码块执行期间,线程始终持有对象的监控权,其他线程处于阻塞状态,只能等待
-
同步代码块是以当前所在对象做锁旗标
synchronized(this) === 同步方法 -
同步静态方法,使用类作为同步标记
public static synchronized xxxx(...){
} -
wait()
让当前线程进入到锁旗标的等待队列,释放cpu抢占权,还释放锁旗标的监控权。
wait(1000); 设定等待时间,可以避免死锁 -
notify()
唤醒在等待队列中的线程,一次只通知一个线程 -
notifyAll()
通知所有线程可以抢占cpu和锁旗标监控权,解决死锁问题class ThreadDemo10{ public static void main(String[] args){ Pool pool = new Pool(); Productor p1 = new Productor("生产者1",pool); p1.setName("p1"); //Productor p2 = new Productor("生产者2",pool); Consumer c1 = new Consumer("消费者1",pool); c1.setName("c1"); Consumer c2 = new Consumer("消费者2",pool); c2.setName("c2"); p1.start(); //p2.start(); c1.start(); c2.start(); } } //生产者 class Productor extends Thread{ private String name; private Pool pool; static int i = 0; public Productor(String name, Pool pool){ this.name = name; this.pool = pool; } public void run(){ //int i=0; while(true){ pool.add(i++); } } } //消费者 class Consumer extends Thread{ private String name; private Pool pool; public Consumer(String name, Pool pool){ this.name = name; this.pool = pool; } public void run(){ while(true){ pool.remove(); } } } //票池 class Pool{ private java.util.List<Integer> list = new java.util.ArrayList<Integer>(); //容器最大值 private int MAX = 1; //添加元素 public void add(int n){ synchronized(this){ try{ String name = Thread.currentThread().getName(); while(list.size() == MAX){ System.out.println(name+".wait()"); this.wait(); } list.add(n); System.out.println(name+"+: "+n); System.out.println(name+".notify()"); this.notifyAll(); } catch(Exception e){ e.printStackTrace(); } } } //删除元素 public int remove(){ synchronized(this){ try{ String name = Thread.currentThread().getName(); while(list.size() == 0){ System.out.println(name+".wait()"); this.wait(); } int i = list.remove(0); System.out.println(name+"-:"+i); System.out.println(name+".notify()"); this.notifyAll(); return i; } catch(Exception e){ e.printStackTrace(); } return -1; } } }
作业
-
一共100个馒头,40个工人,每个工人最多能吃3个馒头,使用多线程输出所有工人吃馒头的情况
-
5辆汽车过隧道,隧道一次只能通过一辆汽车。每辆汽车通过时间不固定,
机动车通过时间3秒,三轮车通过时间5秒,畜力车通过时间10秒,5辆车分别是2辆机动车,2辆畜力车,1辆三轮车,通过多线程模拟通过隧道的情况。提示:Car ThreeCar CowCar -
用多线程模拟蜜蜂和熊的关系
蜜蜂是生产者,熊是消费者,蜜蜂生产蜂蜜是累加的过程,熊吃蜂蜜是批量(满20吃掉)的过程,生产者和消费者之间使用通知方式告知对方,注意不能出现死锁现象。
100只蜜蜂,每次生产的蜂蜜是1
熊吃蜂蜜是20(批量的情况)