集合(LinkedList,Set,TreeSet,Map,TrerMap),集合工具类,异常的处理,二分搜索法,多线程,设计原则

1.LinkedList

LinkedList集合的特点:
	线程不安全的类,执行效率高,连接链表结构,查询慢,增删快;
	
自定义类(工具类):里面提供添加和删除的功能;
里面使用到LinkedList集合功能,必须创建LinkedList集合功能;
特有功能:
	public void addFirst(Object e): 在列表开头插入元素;
	public void addLast(Object e): 将元素追加到列表的末尾;
	public Object getFirst(): 获取列表的第一个元素;
	public Object getLast(): 获取列表的最后一个元素;
	public Object removeFirst(): 删除列表的第一个元素,并获取第一个元素;
	Public Object removeLast(); 删除列表的最后一个元素,并获取最后一个元素;
public class LinkedListDemo {

    public static void main(String[] args) {

        //创建一个LinkedList集合对象
        LinkedList<String> link = new LinkedList<>() ;

        //添加元素
       // public void addFirst(Object e):在列表开头插入元素

       link.addFirst("hello") ;
       link.addFirst("world") ;
       link.addFirst("JavaEE") ;
       link.addFirst("Android") ;


       link.addLast("Php") ;

       //public Object getFirst():获取列表的第一个元素
        System.out.println(link.getFirst());
        System.out.println(link.getLast());

        // public Object removeFirst(): 删除列表的第一个元素,并获取第一个元素
        System.out.println(link.removeFirst());
        System.out.println(link.removeLast());
       System.out.println(link);

    }
}
//自定义一个类,模拟栈结构先进后出的特点(linkedList集合):
public class MyStack<T> {  //泛型:定义类上,定义在方法上,定义接口上
                    //String

    //成员变量,声明LinkedList类型变量
    private LinkedList<T> link ;   //String

    //提供无参构造方法
    public MyStack(){
        //给link初始化
        link = new LinkedList<>() ;
    }

    //提供添加的功能,利用LinkedList的addFirst()
    public void set(T t){//String
        link.addFirst(t);//每一次往列表的开头添加元素
    }
    //提供删除的功能,利用LinkedList的removeFirst():删除并返回第一个元素
    public <T> T get(){//将泛型定义在方法上 //获取的元素 String类型
            return (T) link.removeFirst();  //removeFirst()---->本身Object类型
    }


    //提供一个判断功能
    public boolean isEmpty(){
        return link.isEmpty() ;
    }
}

public class LinkeListTest {
    public static void main(String[] args) {

        //创建MyStack对象
        MyStack<String> myStack = new MyStack<>() ;
        myStack.set("hello");
        myStack.set("world");
        myStack.set("JavaEE");

       while (!myStack.isEmpty()){
           Object obj = myStack.get();
           System.out.println(obj);
       }

    }
}

2.Set集合

Set集合是无序的(存储和取出数据不一致),能够保证元素唯一;
HashSet:底层数据结构是一个哈希表(桶结构);
线程不安全的类---->布不同步---->执行效率高

String 类型:String类型本身已经重写了hashCode()和equals,如果hashCode和equals都相同,那么认为同一个元素,存储以前的值;
如果存储的是自定义对象,如何保证元素唯一?
HashSet集合以来与add方法--->HashMap的put方法
首先要比较元素的哈希码值相同--->hash()就相同
还要比较成员信息是否相同,对应存储定义的类必须要重写Object的equals方法
应用场景:
	在一些需求中,如果没有明确要求元素重复,那就可以使用HashSet,保证元素唯一
public class HashSetDemo2 {

    public static void main(String[] args) {

        //创建HashSet集合对象
        HashSet<Student> hs1 = new HashSet<>() ;

        Student s1 = new Student("宋江",35) ;
        Student s2 = new Student("宋江",35) ;
        Student s3 = new Student("武松",30) ;
        Student s4 = new Student("宋江",30) ;
        Student s5 = new Student("武松",30) ;
        Student s6 = new Student("卢俊义",28) ;
        Student s7 = new Student("卢俊义",28) ;
        System.out.println("-------------------------------");
        //System.out.println(s1.hashCode());
        //System.out.println(s2.hashCode());

        //添加集合中
        hs1.add(s1) ;
        hs1.add(s2) ;
        hs1.add(s3) ;
        hs1.add(s4) ;
        hs1.add(s5) ;
        hs1.add(s6) ;
        hs1.add(s7) ;


        //遍历
        for(Student s : hs1){
            System.out.println(s.getName()+"---"+s.getAge());
        }
    }
}

3.集合嵌套

ArrayList<ArrayList>

例:

public class ArrayListIncludeArrayListTest {

    public static void main(String[] args) {
        //需要创建一个大的集合
        ArrayList<ArrayList<Student>>  bigArray = new ArrayList<>() ;

        //第一个子集合ArrayList<Student>
        ArrayList<Student> firArray = new ArrayList<>() ;
        Student s1 = new Student("高圆圆",42) ;
        Student s2 = new Student("文章",35) ;
        Student s3 = new Student("王宝强",30) ;
        firArray.add(s1) ;
        firArray.add(s2) ;
        firArray.add(s3) ;

        //将第一个子集合添加到大集合中
        bigArray.add(firArray) ;

        //第二个子集合ArrayList<Student>
        ArrayList<Student> secArray = new ArrayList<>() ;
        Student s4 = new Student("张三",42) ;
        Student s5 = new Student("王五",35) ;
        Student s6 = new Student("李四",30) ;
        secArray.add(s4) ;
        secArray.add(s5) ;
        secArray.add(s6) ;

        //将第二个子集合添加到大集合中
        bigArray.add(secArray) ;

        //第三个子集合ArrayList<Student>
        ArrayList<Student> thirArray = new ArrayList<>() ;
        Student s7 = new Student("盲僧",42) ;
        Student s8 = new Student("亚索",35) ;
        Student s9 = new Student("提莫",30) ;
        thirArray.add(s7) ;
        thirArray.add(s8) ;
        thirArray.add(s9) ;

        //将第三个集合添加到集合中
        bigArray.add(thirArray) ;

        //ArrayList<ArrayList<Student>>遍历大集合
        for(ArrayList<Student> array:bigArray){
            for(Student s: array){
                System.out.println(s.getName()+"\t"+s.getAge());
            }
        }
    }
}

4.TreeSet集合

TreeSet集合:无序性,元素唯一;
底层依赖TreeMap集合,红黑树结构(也成为"自平衡的二叉树结构"),可以实现Map的自然排序一骑比较器排序取决于使用的构造方法
构造方法: 	public TreeSet():构造一个空的数,实现元素自然排序(取决于存储的元素类型能否实Comparable接口);
自然排序:执行的TreeSet无参构造方法,而且前提条件当前存储类型必须实现Comparable接口

TreeSet能够实现两种排序:
	自然排序/比较器排序:取决于构造方法;
	自然排序:TreeSet<E>(),E类型必须实现Comparable接口,实现自然排序(实现的是compareTo(T t));
	比较器排序:public TreeSet(Compartor<? super E> comparator)
		Comparator是一个接口类型:
			1)自定义一个类实现Comparator接口,重写compara方法;
			2)使用接口的匿名内部类
		 使用TreeSet存储自定义类型,遍历元素(使用比较器排序完成)

TreeSet集合什么时候使用自然排序什么时候使用比较器排序

根据TreeSet集合的构造方法来判定使用的什么排序

如果使用TreeSet()无参构造方法(需要让存储的元素实现自然排序),前提条件:存储的元素类型必须实现Comparable接口,重写compareTo()方法

如果使用TreeSet(Comparator<T> com)有参构造方法,传递一个接口类型,需要该接口的子实现类对象
使用接口内名内部类的方式实现:
		TreeSet(new Comparator<T>(){
				//重写compare方法
				public int compare(T o1,T o2){
				
						//排序条件。。。
						return int类型的结果;
				}
		
		});
public class TreeSetDemo {

    public static void main(String[] args) {
        //  public TreeSet()
        //Integer类型
        TreeSet<Integer> ts = new TreeSet<>() ;
        //Intger元素 实现Comparable接口---就能够按照元素自然排序(默认升序排序)

        //添加元素
        ts.add(20) ;
        ts.add(17) ;
        ts.add(17) ;
        ts.add(18) ;
        ts.add(24) ;
        ts.add(23) ;
        ts.add(24) ;
        ts.add(19) ;
        //遍历集合TreeSet
        for(Integer i:ts){
            System.out.println(i);
        }

    }
}
//实现自然排序 实现一个接口Comparable
public class Student implements  Comparable<Student>{

    private String name ;//姓名
    private int age ;//年龄


    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.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) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    //排序的代码
    @Override
    public int compareTo(Student s) { 

       //主要条件:按照学生姓名的长度:从小到大进行排序
        int num = this.name.length() - s.name.length() ;

        //如果长度相同,还比较内容是否一样 
        int num2 = (num==0)?(this.name.compareTo(s.name)):num ;
        return num2 ;
    }
}
public class TreeSetDemo2 {
    public static void main(String[] args) {

        //创建TreeSet,无参构造方法
        TreeSet<Student> ts = new TreeSet<>() ;

        //创建几个学生对象
        Student s1 = new Student("gaoyuanyuan",42) ;
        Student s2 = new Student("gaoyuanyuan",42) ;
        Student s3 = new Student("jacky",40) ;
        Student s4 = new Student("rose",40) ;
        Student s5 = new Student("tomcat",35) ;
        Student s6 = new Student("jeffry",35) ;
        Student s7 = new Student("liushishi",54) ;
        Student s8 = new Student("liudehua",60) ;

        //添加
        ts.add(s1) ;        
        ts.add(s2) ;
        ts.add(s3) ;
        ts.add(s4) ;
        ts.add(s5) ;
        ts.add(s6) ;
        ts.add(s7) ;
        ts.add(s8) ;

        //遍历
        for(Student s : ts){
            System.out.println(s.getName()+"---"+s.getAge());
        }

    }
}

5.Map集合

Map集合是双列集合,只能存储同一种类型,存储的是键值对,键必须唯一(Map集合针对键有效,与只无关);
Map集合:键映射到值得对象,Map集合可以多个值,但键必须唯一;
Map集合的功能:
	map.put(K key , V value) : 添加键值对元素;
		注意事项:
				如果key是第一次添加,那么返回的结果为null;
				如果key是重复添加,那么第二次添加,返回的上一次添加的键对应的值
	map.remove(Object key) : 删除指定的键,返回被删除的键对应的值;
	void clear() : 暴力删除, 删除集合中所有的键值对;
	boolean containsKey(Object key) :是否包含指定的键 (使用居多);
	boolean containsValue(Object value):是否包含指定的值;
Map集合遍历方式:
1)
	Set<k> keySet(): 获取所有的键的集合
	Vget(K key): 通过键获取值
2)
	Set<Map.Entry<K,v>> entrySet() : 获取键值对对象;
	键值对:
		K getKey() 通过键值对对象获取键;
		V getValue() 通过键值对对象获取值

HashMap与Hashtable的区别

共同点:底层数据结构是桶结构(基于哈希表实现)
不同点:
	前者是线程不安全,允许元素null(空元素,Key,Value都可以为null),不同步---->执行效率高一些
	后者是线程安全,不允许元素出现null键,和null值,同步---->执行效率低
	
    默认容量大小
	
	
	
	线程安全的类:
		StringBuffer
		Vector
		Hashtable
		Collections的静态功能:
        public static <T> List<T> synchronizedList(List<T> list):将list结构构造成线程安全的列表
		

Map集合与Collection集合的区别:


	单列集合,只能存储一种引用类型,简单记“光棍”
	 遍历方式:
	       集合的迭代器方式进行遍历iterator()/增强for循环
	       针对List接口,该集合遍历方式有5种方式
	       	Objet[] toArray()
	       	size()+get(int index)
	       	Iterator iterator()
	       	ListIterator listIterator()
	       	foreach语句
Map<K,V>集合: 
    	双列集合,可以存储两种引用类型  简单记“夫妻对”
    	遍历方式:
    		Set<K> keySet():获取所有的键的集合
			V get(K key):通过键获取值

			Set<Map.Entry<K,V>> entrySet():获取键值对对象
			键值对:
				K getKey()通过键值对对象获取键
				V getValue()通过键值对对象获取值
				
这两个集合有间接联系
		Collection的子接口Set的具体的实现类:HashSet/TreeSet 他们的add(Object e)
		和HashMap以及TreeMap的put有关系
		
		HashMap	put方法:依赖于hashCode()以及equals()方法
		TreeMap put方法:根据两种情况对集合中的存储元素进行排序
    			

6.TreeMap集合

TreeMap:红黑树结构---针对Map的键按照条件排序---键属于自定义的情况;
键必须唯一而且排序的主要条件:按照学生的年龄从小到大排序;
TreeMap的构造方法:
	public TreeMap():针对键进行自然排序;
	public TreeMap(Comparator<? super K> comparator):针对键按照比较器进行排序;

7.集合工具类Collections

collections是针对集合进行操作的工具类
提供静态功能:
	public static <T extends Comparable<? super T>> void sort(List<T> list):按照自然升序排序(针对List集合排序);
	public static <T> void sort(List<T> list,Comparator<? super T> c):按照比较器排序针对List集合;
	public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T>:获取当前自然顺序中List的最大值;
	public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T>:获取当前自然顺序中List的最小值;
	public static void reverse(List<?> list):对List集合顺序反转;
	public static void shuffle(List<?> list):随机置换;
public class CollectionsDemo1 {
    public static void main(String[] args) {

        //创建List集合
        List<Integer> list = new ArrayList<>() ;

        //添加元素
        list.add(10) ;
        list.add(50) ;
        list.add(15) ;
        list.add(25) ;
        list.add(5) ;
        list.add(12) ;

        System.out.println(list);

        System.out.println("---------------------------------");
        //public static <T extends Comparable<? super T>> void sort(List<T> list):
        Collections.sort(list);
        System.out.println(list);
        System.out.println("----------------------------------");
        //public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T>
        Integer max = Collections.max(list);
        System.out.println(max);
        System.out.println("----------------------------------");
        System.out.println(Collections.min(list));
        System.out.println("-----------------------------------");
        Collections.reverse(list);//反转
        System.out.println(list);
        System.out.println("------------------------------------");
        //  public static void shuffle(List<?> list):随机置换
        Collections.shuffle(list);
        System.out.println(list);

    }
}

8.System类

System类不能进行实例化;
成员变量:
	public static final InputStream in:标准输入流;
	public static final PrintStream out:标准输出流;
	public static final PrintStream err:错误输出流(打印错误信息/一些信息需要用户引起注意:相关的日志);
	System.exit(0) :jvm退出 ,0表示正常终止;
	public static void gc():手动开启垃圾回收器,会去回收内存中没有更多引用的对象;

9.异常的处理

Throwable:包含所有的错误以及异常! 它是一个超类(父类);
	error:非常严重问题  (跟代码没有太大有关系):OOM Out Of Memory:内存溢出 (严重问题);
	Exception:异常
	编译时期异常和运行时期异常(RuntimeException):程序在运行过程中出现问题,只要不是RuntimeException的子类都是属于编译时期异常;
	运行时期异常:在程序.程序代码逻辑问题
	

异常的两种处理方式:

1)标准格式:try...catch...finally
	变形格式:
	 try{
         //可能出现问题的代码
        }catch(异常类名 变量名){
         //处理异常
         }
         try{
         //可能出现问题的代码
         }catch(异常类名 变量名){
          //处理异常1
          }catch(异常类名 变量名){
           //处理异常2
          }
          try{
          //可能出现问题的代码
            }finally{
           //释放资源(系统资源)
            }
2)throws:抛出

①有的时候没有办法去抛出,继承关系中,如果子类继承父类,父类的该方法没有异常,子类重写该方法的时候,只能try...catch
②子类继承父类,如果父类的该方法本身抛出异常了,那么子类重写该方法的时候,要么跟父类的方法的异常类名一致,要么是该异常的类子类!

编译时期异常和运行时期异常的区别?

RuntimeException:运行时期异常:一般程序员逻辑结构不严谨导致的问题,调用者可以进行显示处理(try...catch.../throws),也可以不进行显示处理,通过逻辑语句进行处理
	很多的子类:NullPointerException,ClassCastException,ArrayIndexOutOfBoundsException....;
编译时期异常:调用者必须显示处理,不处理,编译通过不了,程序运行不了
	如果在当前方法中已经去捕获了try...catch...,调用者无序进行处理,但是如果在方法中抛出异常的,调用者必须处理(捕获/抛出throws)
	
在开发中:尽量优先使用try...catch异常,其次再是throws

throws和throw的区别?

共同点:都是抛出
用法不同:
	1)使用位置不同
		throws:
			a)将异常抛出在方法声明上
			b)在方法名的后面可以跟多个异常类名,中间逗号隔开!
		throw:
			a)在方法的语句体中某个逻辑语句中
			b)它后面只能跟异常对象,而不是类名
	2)调用者是否处理不同:
		throws:调用者必须进行显示处理(try...catch/throws),否则报错;
		throw:调用者无须显示处理,一般情况都是在逻辑语句进行处理;
	3)出现异常是否肯定性
		throws:在方法上的,执行某个方法的代码中,可能有问题(表示出现异常的一种可能性);
		throw:执行某段代码一定会执行这个异常(表示出现异常的一种肯定性)
	4)
		throws---->将具体的处理交给jvm---通过jvm吧异常信息打印控制台上,显示的底层源码而且会显示当前错误消息字符串;
		throw---->程序 中某段代码有问题:只是打印异常类名(jvm处理)
不管使用throws/try...catch...finally:
     都是要通过jvm调用Throwable里面的功能完成日志(错误信息)打印
         try{
            //可能出现问题的代码   //首先加载这些代码 (语法校验)
         }catch(异常类名 变量名){       //如果存在问题,那么jvm在内存中创建异常的实例,实例是否为catch语句中类型的实例
          //类似于  a instanceOf 引用类型:如果是就会执行catch语句
                                                                 
            异常处理                                //要么手动处理/要么通过jvm进行处理(打印错误日志信息)
        }finally{
            释放资源...
        }

       Exception----->Throwable
        public String getMessage()获取详细消息字符串   同义的方法:public String getLocalizedMessage()
        public String toString():打印出当前异常信息的简短描述:
                内存中异常对象的类名:(全限定名称:包名.类名) 换行
                “:”(一个冒号和一个空格)  换行
                 public String getMessage():消息字符串


        //public void printStackTrace():跟踪堆栈:包含toString以及底层原码(某行代码出现问题)以及本类中的代码问题
                       都是体现方法上(将当前跟方法相关的底层方法全部跟踪一遍)


finally:不能单独使用,它是结合try...catch....finally:异常的标准格式
              finally用法:
                       特点:
                              释放相关的资源,代码一定执行的
                               除非在执行finally,jvm退出了!
如果在某个方法中捕获异常,但是该方法有返回值类型,如果在catch语句出现return语句,finally代码还会执行吗?如果会执行,在return前还是在后

	 finally会执行,但是现在这个代码,在catch语句已经形成返回路径,它会记录最终返回就是30;finally是去释放资源用的,

10.二分法搜索

数组高级查找算法之二分法搜索的前提条件是数组必须有序,如果数组无序,则先排序再查找;

public class BinarySearch {

    public static void main(String[] args) {
        //已知数组,静态初始化
        int[] arr = {11,22,33,44,55} ;
        //调用二分搜索方法查询
        int index = binarySearch(arr, 22);
        System.out.println(index);
        int index2 = binarySearch(arr,66) ;
        System.out.println(index2);
        int index3 = binarySearch(arr,44) ;
        System.out.println(index3);

        System.out.println("-----------------------------------");
        int index4 = Arrays.binarySearch(arr, 55);
        System.out.println(index4);
        int index5 = Arrays.binarySearch(arr, 66);
        System.out.println(index5);


    }
    //返回值int
    //方法参数:数组,查询的元素
    public static int binarySearch(int[] arr,int target){
        //防止空指针异常
        if(arr!=null){
            //定义数组的最小索引:
            int min = 0 ;
            //定义最大索引
            int max = arr.length -1 ;
            //使用循环while
            while(min<=max){
                //计算中位点索引
                int mid = (min+max)/2 ;

                //如果当前中位点对应的元素小于要要查找的元素
                if(target < arr[mid]){
                    //左半区域:继续折半
                    max = mid -1 ;
                }else if(target > arr[mid]){
                    //右边区域:继续折半
                    min = mid + 1 ;
                }else{
                    //查询到了
                    return mid ;
                }
            }
        }
        //循环结束之后,还没有找,则返回-1
        return -1 ;

    }
}

11.多线程

线程是依赖于进程的;

进程:能够调用的系统资源的独立单位;
线程:属于程序执行中的最小的单元(进程中的一条任务线);一个进程由多个线程组成,多个线程组成线程组;

多线程的意义:
	多线程的特点:具有随机性,多个线程在抢占CP的执行权

Thread类的方法

构造方法:
	Thread(String name):创建线程类对象,设置名称;
成员方法:
	public final String getName():获取线程名称;
	public final void setName(String name):设置线程名称;

线程的优先级

Thread类中静态常量字段(成员变量field)
public static final int MAX_PRIORITY 10     最大优先级
public static final int MIN_PRIORITY 1      最小优先级
public static final int NORM_PRIORITY 5     默认优先级
public final void setPriority(int newPriority):设置线程的优先级
public final int getPriority():获取优先级;
优先级越大的:抢占CPU的执行权越大;
优先级小的:抢占CPU的执行权越小;

创建线程的方式:

1)继承Thread类
	a)将一个类声明为Thread类的子类;
	b)这个类应该重写Thread类的run()方法;
	c)然后可以分配并启动子类的实例。
2)实现Runnable接口
	a)实现类需要重写run()方法;
	b)在main用户线程中创建类的实例;
	c)创建当前类的对象,然后创建Thread类对象,将当前了对象作为参数来传递;
	d)分别启动线程
//线程类
public class MyThread2 extends Thread {


    //t1,t2
    @Override
    public void run() {
        for(int x = 0 ; x < 100 ; x ++){
            //获取线程名称
            System.out.println(this.getName()+":"+x);
        }
    }
}
public class ThreadDemo2 {
    public static void main(String[] args) {//用户线程

        //创建MyThread2类的对象
        MyThread2 t1 = new MyThread2()  ;
        MyThread2 t2 = new MyThread2()  ;
        MyThread2 t3 = new MyThread2()  ;


        // public final void setName(String name):设置线程名称
        t1.setName("洪学佳") ;
        t2.setName("张俊杰") ;
        t3.setName("高圆圆");

        t1.setPriority(10); //最大优先级
        t2.setPriority(1);//最小优先级

        int num1 = t1.getPriority();
        int num2 = t2.getPriority();
        int num3 = t3.getPriority();
        System.out.println(num1+"---"+num2+"---"+num3);

        //启动线程
        t1.start();
        t2.start();
        t3.start();



    }
}

public final void join() throws InterruptedException:等待该线程终止;

public static void yield():暂停当前正在执行的线程,执行对方线程;

 public final void setDaemon(boolean on);参数为true,表示标记当前线程为守护线程,当正在运行的线程如果都是守护线程,则jvm自动退出,这个方法必须在启动线程之前调用(start()之前)

线程的六种状态

Thread类内部枚举类
public enum State{
	NEW,			新建 (未执行)
	RUNNABLE,		运行状态 (可能出现阻塞的情况)
	BLOCKED,        线程阻塞状态(wait,sleep...)
	WAITTING,		死死等待(底层调用wait()方法)
	TIMED_WAITTING, 超时等待(直接调用wait(long timeout))
	TERMINATED;		线程终止死亡状态(线程执行完毕)
}

检验线程安全问题的标准

1)是否存在多线程环境;
2)是否存在共享数据;(资源类的数据)
3)是否存在多条语句对共享数据的操作;

同步机制synchronized(锁对象)

锁对象:必须要多个线程使用同一个锁对象,而不是分别使用自己的锁对象

格式:
	synchronizexd(锁对象){
		多条共享数据;
	}

静态代理

Thread类:就是代理类
自定义的MyRunnable implement Runnable   --->真实角色

静态代理:
		真实角色:只专于自己的事情(自己的业务功能)
		代理类:帮助真实角色完成一些事情(针对真实角色的业务功能进行增强)
		代理类和真实角色都需要实现同一个接口!
		
动态代理:在程序中的过程中通过反射的这种反射产生代理角色	
		jdk动态代理:基于接口的一种代理 (反射)
		cglib:基于子类的一种代理(Spring)

public class ThreadDemo {
    public static void main(String[] args) {

        //接口多态
        //Mary mary = new You() ;
        You mary = new You() ;
        mary.mary();
        System.out.println("----------------------");

        //静态代理:通过婚庆公司帮助自己You来完成结婚
        //真实角色
        You you2  = new You() ;     // MyRunnable
        WeddingCompany wc = new WeddingCompany(you2) ;// Thread类对象
        wc.mary();
    }
}

//定义一个接口的接口
interface  Mary{
    void mary() ;//结婚
}

//自己:真实角色
class You implements  Mary{

    @Override
    public void mary() {
        System.out.println("结婚了,很开心...");
    }
}

//代理角色:婚庆公司 在你结婚之前,它可以给你布置婚礼线程, 结婚之后,开开心心吃席
class WeddingCompany implements Mary{

    //将真实角色作为参数传递

    private You you ;
    public WeddingCompany(You you){
        this.you = you ;
    }


    @Override
    public void mary() {
        System.out.println("给你布置婚礼现场...");

        you.mary();  //只要专注于自己的事情!

        System.out.println("婚礼线程布置完毕,吃席...");
    }
}

电影院售票

public class SellTicket implements Runnable {

    //成员变量;100张票
    public static int tickests = 100 ;

    //创建一个锁对象:
    public Object obj = new Object() ;


    //t1,t2,t3
    @Override
    public void run() {
        //模拟一直票
        while(true){
           synchronized (obj){
                //模拟网络延迟
                //判断
                if(tickests>0){//100>0
                    try {
                        Thread.sleep(100); //单位为毫秒数
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    //输出窗口信息
                    System.out.println(Thread.currentThread().getName()+"正在出售第"+(tickests--)+"张票");
                }
            }
        }

    }
}
public class SellTicketTest {

    public static void main(String[] args) {
        //创建资源类对象SellTicket
        SellTicket st = new SellTicket() ;

        //创建三个线程类对象
        Thread t1 = new Thread(st,"窗口1") ;
        Thread t2 = new Thread(st,"窗口2") ;
        Thread t3 = new Thread(st,"窗口3") ;

        //分别启动线程
        t1.start();
        t2.start();
        t3.start();
    }
}

什么是同步方法?

如果一个方法的方法体的第一句话就是同步代码块,可以将synchronized关键字提取到方法声明上,跟在权限修饰符的后面,
	权限修饰符 synchronized 返回值类型 方法名(形式列表){  
		业务逻辑...
	}

sleep和wait方法的区别?

1)调用方法是是否会释放锁
sleep(long mills)线程睡眠,调用等待睡眠时间到了,继续线程执行,不会去释放锁
wait的方法调用会立即释放锁对象,目的就是为了让锁对象调用notify()来唤醒其他线程...
2)来源不同
	sleep方法来源于Thread类
			属于线程的功能---->线程执行过程中可能产生阻塞 (睡眠一段时间内是阻塞的)
			
	wait方法来源于Object类
			它和锁对象有关系,线程处于等待过程中 使用锁对象.wait() 
3)共同点:都会抛出一个异常:InterruptedException:中断异常			

wait()方法与notify()方法

也可以称为"同步"  --->等待唤醒机制
线程等待/线程唤醒 这些方法为什么不定义在Thread类中呢,而是定义Object类中呢?
因为它和锁对象有关系,而锁对象:可以任何的java类对象,-----Object(顶层父类)
	syncronized(锁对象){
		锁对象.wait();
		或所多对象.notify();
	}

线程安全与死锁问题

线程安全问题:可以通过同步方法或者是同步代码块去解决,但是执行过程中就可能出现死锁问题;
死锁问题:(使用同步机制解决线程安全) 线程和线程之间出现了互相等待的情况!
	解决方案:多个线程之间的通信:必须使用的是一个资源类对象,而不能是每一个线程在使用自己的资源类对象!使用生成者和消费者模式思想去解决,前提条件:生成者线程和消费者线程 必须操作的同一个资源类对象!
使用生产者和消费者思想解决线程死锁问题

例:生产包子和吃包子

public class StuffBun {
    //成员变量不私有化
    String name ;//包子的类型(肉包子,菜包子)
    String bunType ;//大包子/小包子

    //定义标记:表示是否存在包子数据
    boolean flag ; //默认false
}
//生产者类
public class SetBun implements  Runnable {

    //声明这个包子类
    private StuffBun stu ;
    public SetBun(StuffBun stu){
        this.stu = stu ;
    }

    //定义一个统计变量
    int x = 0 ;

    @Override
    public void run() {
        //产生包子
      //不断的产生数据
      while(true){
          synchronized (stu){
              //如果当前生产者没有语句,需要等待生成产生数据
              if(stu.flag){
                  //锁对象调用wait发那个发
                  try {
                      stu.wait();//释放锁对象...
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }

              if(x % 2 == 0){//t1
                  stu.name = "肉包子" ;
                  stu.bunType = "大包子";
              }else{
                  stu.name = "菜包子" ;
                  stu.bunType = "小包子" ;
              }

              //如果现在有数据了
              //改变信号
              stu.flag  = true ;//有数据类
              //通知(唤醒)消费者线程,赶紧使用数据
              stu.notify(); //唤醒对方线程
          }
          x ++ ;
      }
    }
}
//消费者类
public class GetBun implements Runnable {
    //声明包子类的变量stb
    private StuffBun stu ;
    public GetBun( StuffBun stu){
        this.stu = stu ;
    }

    @Override
    public void run() {

        //模拟要使用数据
      //  StuffBun stb = new StuffBun() ;
        //不断使用数据
        while(true){
            synchronized (stu){
                //如果当前消费资源类中存在包子数据,先等待消费使用完毕数据
                if(!stu.flag){
                    //等待使用完毕数据
                    try {
                        stu.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                System.out.println(stu.name+"---"+stu.bunType);


                //改变信号值
                //如果包子消费完毕
                stu.flag = false ;
                //唤醒对方线程(生产者资源类,别等了,产生数据)
                stu.notify();
            }
        }
    }
}
//测试类
public class ThreadDemo {
    public static void main(String[] args) {

        //创建一个包子对象
        StuffBun sbu  = new StuffBun() ; //同一个对象

        //创建生产资源类对象
        SetBun sb = new SetBun(sbu) ;
        //消费者资源类对象
        GetBun gb = new GetBun(sbu) ;

        //创建线程了对象
        Thread t1 = new Thread(sb) ;//生产者资源类所在的生产者线程
        Thread t2 = new Thread(gb) ;//消费者资源类所在的消费者线程

        t1.start();
        t2.start();

    }
}

Lock

JDK5以后提供java.util.current.locks.Lock   :提供比syncrhonized方法(/同步代码块)更具体的锁定操作
多个线程并发访问,抢占共享资源数据,通过lock实现多个线程对某个共享资源进行独占访问,不会出现安全问题

Lock是一个接口:
	void lock():获取锁
	void unlock():释放锁
	提供具体的自实现类:
		ReentranLock

实现电影院卖票

public class SellTicket implements  Runnable {

    //定义100张票
    private static int tickets = 100 ;

    //创建一个锁对象
    Lock lock = new ReentrantLock() ;

    @Override
    public void run() {
        //模拟一只有票
        while(true){

            //通过锁对象--->获取锁
            lock.lock();
            //try...catch...finaly:捕获异常
            //使用try..finally
            try{
                //判断
                if(tickets>0){

                    //睡眠100毫秒
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName()+"正在出售第"+(tickets--)+"张票");
                }else{
                    break ;
                }
            }finally {
                //释放锁
                lock.unlock();
            }



        }
    }
}
public class LockDemo {


    public static void main(String[] args) {
            //创建共享资源类对象
        SellTicket st = new SellTicket() ;
        //创建三个线程类对象
        Thread t1 = new Thread(st,"窗口1") ;
        Thread t2 = new Thread(st,"窗口2") ;
        Thread t3 = new Thread(st,"窗口3") ;

        //启动线程
        t1.start();
        t2.start();
        t3.start();
    }
}

线程组:

线程组代表一组线程.此外,线程组还可以包括其他线程组;
Thread: 
	获取线程组:
	public final ThreadGroup getThreadGroup(){
		return group;
	}
	给线程组设置默认的线程组名称:
	public Thread(ThreadGroup group , Runnaqble target){};
	ThreadGroup:
	获取默认线程组的名称:
	public final String getName(){
		return name;
	}
	构造方法:
		public ThreadGroup(String name){}
线程组:将线程可以都添加一组中,方便管理,线程启动完毕后,线程终止之后,不会将这个线程对象在内存中重复利用
public class ThreadGroupDemo {
    public static void main(String[] args) { //jvm调用main方法

      //  method1();
        method2() ;
    }

    //设置一个新的线程组名称
    private static void method2() {
        //创建一个线程组对象--同时设置线程组名称
        ThreadGroup tg = new ThreadGroup("myMain") ;
        //创建两条线程对象
        MyThread my = new MyThread() ;
        Thread t1 = new Thread(tg,my) ;
        Thread t2 = new Thread(tg,my) ;
        //获取线程组对象并同时线程组名称
        String name1 = t1.getThreadGroup().getName();
        String name2 = t2.getThreadGroup().getName();
        System.out.println(name1+"---"+name2);
    }

    private static void method1() {

        //创建两个线程
        MyThread my  = new MyThread() ;
        Thread t1 = new Thread(my) ;
        Thread t2 = new Thread(my) ;
        ThreadGroup tg1 = t1.getThreadGroup();
        ThreadGroup tg2 = t2.getThreadGroup();
        String name1 = tg1.getName();
        String name2 = tg2.getName();
        System.out.println(name1+"---"+name2);  //默认线程组名称都是main


    }
}

线程池

线程池属于"池"化技术
特点:
	在内存中创建一个固定可重用的线程数,当前线程执行完毕终止了,不会被回收掉,再次回到线程池中,等待下一次使用
弊端:
	维护成本大
ExecutorService:提交队列任务(多个线程并发执行)
<T>Future<T>submit(Callable<T> task)提交值返回任务以执行,并返回代表任务待处理结果的Future
Future<?>submit(Runnable task)
submit的返回值:异步计算的结果,如果不做计算,无须返回结果

打印-0-99的数

public class MyCallable implements Callable {
    @Override
    public Object call() throws Exception {
        for(int x = 0 ; x < 100 ; x++){
            System.out.println(Thread.currentThread().getName()+":"+x);
        }

        return null;
    }
}
public class ThreadPoolDemo {
    public static void main(String[] args) {

        //通过工厂类创建线程池对象
        ExecutorService threadPool = Executors.newFixedThreadPool(2);

        //提交异步方法
        //MyRunnable:打印x的值0-99之间的数据,不需要返回结果
      //  threadPool.submit(new MyRunnable()) ;
      //  threadPool.submit(new MyRunnable()) ;
        //   <T> Future<T> submit(Callable<T> task)
        //Callable:提交异步计算---需要重写Callable的call来计算结果;如果没有结果,直接在call无须返回

        threadPool.submit(new MyCallable()) ;
        threadPool.submit(new MyCallable()) ;

        //void shutdown()关闭线程池
        threadPool.shutdown();


    }
}

12.设计原则

开闭原则:
	对现有代码修改关闭,对扩展代码开放;
接口分离原则:
	一个接口中定义一个功能,接口和接口之间独立的,不能相互影响;
里式替换原则:
	任何父类中出现的地方都可以子类替代;
23中设计原则都需要遵循"低耦合,高内聚"原则;

设计模式

设计模式是一种思想,前人总结出来的,不是技术
创建型:对象的创建(使用最多);
创建型设计模式:
	简单工厂:称为静态工厂方法模式;
	优点:利用多态创建子类对象,能够灵活的去创建对象(提供的静态功能)
	弊端:代码量大,一旦有新的类型增加,工厂类的静态功能就需要改动
结构型:整个结构的组成
行为型:具备功能性的;

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值