Java基础8-多线程;同步代码块

作业解析

  1. 利用白富美接口案例,土豪征婚使用匿名内部类对象实现。

     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");
                 }    
             });
         }
     }
    
    
  2. 定义三角形类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);
         }
     }
    
    
  3. Person类中增加birthday属性,对setBirthday(int ,int , int )方法进行异常处理,
    要求年有效、月有效、日有效、年月日指定的具体日期有效,对不同情况分别抛出不同的异常。
    year:>1970, month:1-12, day:1-31

     class 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);
         }
     }
    
    
  4. 将类定义到指定的包下。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包
      
      
  5. 相互之间使用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
      
      
  6. 设计程序,考查修饰符。public -> protected -> default -> private(选做题)

  7. 编写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/ .
      
      
  8. 预习多线程。

进程

  1. 运行时(runtime)的应用程序

  2. 进程之间的内存不是共享(独占)

  3. 进程间通信使用的socket(套接字)
    进程之间内存是隔离的。内存不共享。

多线程

  1. 程序(进程)执行过程中,并发执行的代码段

  2. 线程之间共享内存

  3. 创建灵活响应的桌面程序

  4. 每个运行着的线程对应一个stack(方法栈)

  5. 应用程序至少有一个线程(主线程)

java.lang.Thread

  1. Thread.yield()方法:让当前线程让出CPU抢占权,具有谦逊之意,瞬时的动作

  2. Thread.sleep(int mils)方法:让当前线程休眠指定毫秒数,放弃cpu抢占权,和锁旗标(监控权)没有关系

  3. Thread.join():当前线程等待指定的线程结束后才能继续运行

  4. daemon:守护线程,服务员 Thread.setDaemon(true),为其他线程提供服务的线程。若进程中剩余的线程都是守护线程的话,则进程终止了。

  5. \(--\) 原子性操作

  6. 线程间通信,共享资源的问题。锁, 将并行转串行,防止并发访问。参照物,锁旗标

     //同步代码块
     synchronized(object lock){
     ...
     }
    

    同步代码块执行期间,线程始终持有对象的监控权,其他线程处于阻塞状态,只能等待

  7. 同步代码块是以当前所在对象做锁旗标
    synchronized(this) === 同步方法

  8. 同步静态方法,使用类作为同步标记
    public static synchronized xxxx(...){
    }

  9. wait()
    让当前线程进入到锁旗标的等待队列,释放cpu抢占权,还释放锁旗标的监控权。
    wait(1000); 设定等待时间,可以避免死锁

  10. notify()
    唤醒在等待队列中的线程,一次只通知一个线程

  11. 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;
    		}
    	}
    }
    

作业

  1. 一共100个馒头,40个工人,每个工人最多能吃3个馒头,使用多线程输出所有工人吃馒头的情况

  2. 5辆汽车过隧道,隧道一次只能通过一辆汽车。每辆汽车通过时间不固定,
    机动车通过时间3秒,三轮车通过时间5秒,畜力车通过时间10秒,5辆车分别是2辆机动车,2辆畜力车,1辆三轮车,通过多线程模拟通过隧道的情况。提示:Car ThreeCar CowCar

  3. 用多线程模拟蜜蜂和熊的关系
    蜜蜂是生产者,熊是消费者,蜜蜂生产蜂蜜是累加的过程,熊吃蜂蜜是批量(满20吃掉)的过程,生产者和消费者之间使用通知方式告知对方,注意不能出现死锁现象。
    100只蜜蜂,每次生产的蜂蜜是1
    熊吃蜂蜜是20(批量的情况)

posted @ 2018-10-25 10:01  Shinesu  阅读(204)  评论(0编辑  收藏  举报