Week05手写笔记

本周内容

1. List集合的三个子实现类的特点
1. ArrayList
1.ArrttyList:是我们通用的,单线线程中,它的执行效率高,当没有提示什么list集合的时候,默认使用ArrayList来执行
	底层数据结构是数组结构,特点:查询快,增删慢
	从线程角度考虑,是一个线程不安全的类---->不同步-->执行效率高
扩容性:1.5倍
1.2 Vectot
	底层数据结构是数组结构,特点:查询快,增删慢
	从线程角度考虑:是一个安全的类-->是同步的--->执行效率低
		多线程环境下使用的是线程安全的类
1.3 Linklist
底层数据结构是一个链表实现:查询慢,增删快
     从线程角度: 线程不安全的类---->此实现不同步---->执行效率高
1.1 使用ArrayList模拟登陆和注册

2.Vector的特有功能
public void addElement(E obj):在vector的末尾添加一个新的元素
public E elementAt(int index):获取指定位置处的元素
public Enumeration<E> elements():就类似于迭代器样,vector的特有方法 Enumeration接口的两个特有方法:
	 boolean  hasMoreElements():是否有更多的组件(元素)可以遍历----类似于迭代器接口中的boolean  hasNext()
 E nextElement():获取下一个元素--- 类似于迭代器接口中的 E next()      
 
 因此,list集合多了两种遍历方式:
方式一:public E elementAt(int index)和size()方法相结合普通for
方式二: public Enumeration<E> elements():Vector的特有的迭代器的操作
 Enumeration<String> enumeration = vector.elements();
        while(enumeration.hasMoreElements()){
            String s = enumeration.nextElement();
            System.out.println(s);
        }
3.LinkedList集合特有功能
底层数据结构是一个链表实现:查询慢,增删快
从线程角度考虑:线程不安全的类---->此实现不同步---->执行效率高
单线程只考虑效率问题,多线程环境必须先考虑安全性;
特有功能:
 public void addFirst(Object e):将任何类型的元素每次添加到链表的开头
public void addLast(Objet e):将任何类型的元素每次条件到链表的末尾
public Object removeFirst()从此列表中删除并返回第一个元素。
public Object removeLast()从此列表中删除并返回最后一个元素
public Object getFirst():获取链表的第一个元素
public Object getLast):获取链表的最后个元素
4.set集合特点以及两个子实现类HashSet和TreeSet的使用
4.1 Set的特点及方法
特点:1)不包含重复元素,元素唯一
2)无序性:存储和取出是不一致的
4.2 子实现类HashSet的特点和去重
特点:存储元素和取出,不保证迭代次序是恒久不变的
从源码结构出发:HashSet依赖于HashMap的put方法--->依赖于object类的equals方法和hashcode方法
自定义对象所在的类必须重写object的equals方法和hashcode方法
去重:哈希码值一样,还需要确定成员的信息内容都相同,如果都相同,那么就认为是同一个对象,则只录入一个;
4.3 TreeSet(重点)
属于set集合的子实现类,元素唯一,但是顺序不唯一---跟带主要条件的排序有关
从原码结构分析TreeSet底层结构是一个red-black-tree:红黑树结构
使用不同的构造方法,完成的排序方式也不一样;
自然排序:treeset()无参构造方法
public TreeSet(Comparator<E> comparator):有参构造方法
也就是说这个集合不单独的就是存和取的,而是要按照"某种条件"排序的!

4.3.1 红黑树结构
红黑树结构就是一种"自平衡的二叉树结构";
存储时,将第一次存储的元素作为"根节点":root
后面的元素依次要和这个元素进行比较,如果当前值大于根节点,作为右孩子(右子节点),如果小于根节点,则作为左孩子(左子节点);
取元素时,遵循"前序遍历,中序遍历,后续遍历",也就是从小到大,从左往右
//return -1; //-1表示放在红黑树的左边,即逆序输出
//return 1;  //1表示放在红黑树的右边,即顺序输出
//return o;  //表示元素相同,仅存放第一个元素
4.3.2 自定义对象的treeSet方法一:自然排序
自然排序:使用treeSet无参构造方法,自定义对象实现compareable接口,重写compareable接口的compareTo方法,重写是要加主要条件和次要条件
public class TreeSetDemo2 {
    public static void main(String[] args) {
        TreeSet<Student> t = new TreeSet<>();
        Student s = new Student("张三",98,95,90);
        Student s1 = new Student("李四",95,98,90);
        Student s2 = new Student("王五",95,98,91);
        Student s3 = new Student("赵六",91,98,95);
        t.add(s);
        t.add(s1);
        t.add(s2);
        t.add(s3);
        for(Student st:t) {           System.out.println(st.getName()+"\t"+st.gettotol()+"\t"+st.getChinaGrade()+"\t"+st.getEnglishGrade()
                    +"\t"+st.getMathGrade());}
Student类:
public class Student implements Comparable<Student>{
    private String name;
    private  int chinaGrade ;
    private  int mathGrade;
    private  int englishGrade ;
public int gettotol(){
    return chinaGrade+mathGrade+englishGrade;
}

    public Student() {
    }

    public String getName() {
        return name;
    }

    public int getChinaGrade() {
        return chinaGrade;
    }

    public int getMathGrade() {
        return mathGrade;
    }

    public int getEnglishGrade() {
        return englishGrade;
    }

    public Student(String name, int chinaGrade, int mathGrade, int englishGrade) {
        this.name = name;
        this.chinaGrade = chinaGrade;
        this.mathGrade = mathGrade;
        this.englishGrade = englishGrade;
    }
    @Override
    public int compareTo(Student s) {
        int num = s.gettotol()-this.gettotol();
        int num1 = (num==0)?s.chinaGrade-this.chinaGrade:num;
        int num2 = (num1==0)?s.mathGrade-this.mathGrade:num1;
        int num3 = num2==0?s.englishGrade-this.englishGrade:num2;
        return num3;
    }
}
结果:
王五	284	95	91	98
赵六	284	91	95	98
张三	283	98	90	95
李四	283	95	90	98
4.3.3 自定义的treeSet方法二:选择器排序
选择器排序:使用treeSet(comparator接口)有参构造方法(参数就是comperator对象),接口作为形式参数,接口的匿名内部类李或者子实现类实现compare方法
//测试类
public class TreeSetDemo {
    public static void main(String[] args) {

        TreeSet<Student> t = new TreeSet<>(new Comparator<Student>() {//匿名内部类
            @Override
            public int compare(Student s1, Student s2) {
                int num = s2.gettotol() - s1.gettotol();
                int num1 = (num == 0) ? s2.getChinaGrade() - s1.getChinaGrade() : num;
                int num2 = (num1 == 0) ? s2.getMathGrade() - s1.getMathGrade() : num1;
                int num3 = num2 == 0 ? s2.getEnglishGrade() - s1.getEnglishGrade() : num2;
                return num3;
            }
        });
    Student s = new Student("张三", 98, 95, 90);
    Student s1 = new Student("李四", 95, 98, 90);
    Student s2 = new Student("王五", 95, 98, 91);
    Student s3 = new Student("赵六", 91, 98, 95);
        t.add(s);
        t.add(s1);
        t.add(s2);
        t.add(s3);
        for (Student st : t) {
            System.out.println(st.getName() + "\t" + st.gettotol() + "\t" + st.getChinaGrade() + "\t" + st.getEnglishGrade()   + "\t" + st.getMathGrade());    
        }
    }
}
//学生类正常提供构造方法和set/get即可
5. 需求:一个班级就是arraylist,现在有这么一个班级,arraylist<arraylist,添加并且遍历(ArrayList的嵌套)
public class Test1 {
    public static void main(String[] args) {
        //创建一个大的集合类对象
        ArrayList<ArrayList<Student>> bigArray = new ArrayList<>() ;
        //创建三个子集合--->每一个java班级
        ArrayList<Student> array1 = new ArrayList<>() ;
        //里面添加两个学生数据
        Student s1 = new Student("刘备",35) ;
        Student s2 = new Student("曹操",40) ;
        array1.add(s1) ;
        array1.add(s2) ;
        //将小集合添加到大集合中
        bigArray.add(array1) ;
        //第二个子集合
        ArrayList<Student> array2 = new ArrayList<>() ;
        //里面添加两个学生数据
        Student s3 = new Student("唐僧",50) ;
        Student s4 = new Student("孙悟空",42) ;
        array2.add(s3) ;
        array2.add(s4) ;
        //将小集合添加到大集合中
        bigArray.add(array2) ;
        //第三个子集合
        ArrayList<Student> array3 = new ArrayList<>() ;
        //里面添加两个学生数据
        Student s5 = new Student("宋江",39) ;
        Student s6 = new Student("西门庆",28) ;
        array3.add(s5) ;
        array3.add(s6) ;
        //将小集合添加到大集合中
        bigArray.add(array3) ;
        //方便遍历---->增强for
        //当前大集合的数据类型: ArrayList<ArrayList<Student>>
        System.out.println("学生的信息如下");
        for(ArrayList<Student> myArray:bigArray){

            //子集合ArrayList<Student> --->里面的数据类型就是Student
            for(Student s :myArray){
                System.out.println("\t"+s.getName()+"\t"+s.getAge());
            }
        }
    }
}

6.map的引入
定义:map<k,v>集合 宏观集合:世界事物的实体类;
	微观意义:将键映射到值的对象---表示一系列键值对元素
Map针对键有效,跟值无关,值可以重复,但是键必须是唯一的,不能重复!
所以实际应用场景中,每一个键对应一个值;
K----键值---由此地图维护的键的类型
V----映射值的类型 
6.1 map集合特点(重点)
Map是一个接口不能实例化,通过具体的子实现类来实例化:
通用的子实现类HashMap--->基于哈希表的实现Map接口
特点:允许null的值和null键--->说明---HashMap是一个线程不安全的--->不同步---->执行效率高!
HashMap不能保证迭代次序恒久不变
功能:
int size():获取集合是元素数
当HashMap的值是空的时候,则返回{}--表示一个空的实体类;
添加:
 	public V put(K key,V value):添加键值对元素,返回的值
 		如果key不重复,第一次添加,返回值是--->null
 		如果key重复,再次添加,则后面的V会覆盖前面的V,并且返回前面的V
    	通过key是否为null,来判断它是否是重复添加的!
删除:
	 public V remove(Object key):删除指定的键,返回被删除的键对应的值()如果删除不存在的键值,则返回null
	 public void clear():暴力删除---清空了(所有键值对象元素删除)
判断:
	 public boolean containsKey(Object key):判断是否包含指定的键
	 public boolean containsValue(Object value):是否包含指定的值
	 public boolean isEmpty():判断集合是否为空
6.2 map的特有功能(遍历)
HashMap是基于HashCode和equals方法,所以当键值是自定义对象时,自定义类必须重写HashCode和equals方法;
方式一(建议):Set<K> keySet():获取所有的键值
然后遍历所有的键值,再根据方法V get(key)获取键值对应的value值

方式二:Set<Map.Entry<K,V>> entrySet():获取所有键值对的对象
	然后遍历出所有所有键值对的对象,然后按下边方法取出键值
		K getKey():获取此对象相对应的键
		V getValue():获取此对象相对应的值:value
public class HashSetDemo {
    public static void main(String[] args) {
//创建HashSet对象
        HashMap<String, String> map = new HashMap<>();
        //添加键值对
        map.put("高圆圆","赵又廷");
        map.put("文章","姚笛");
        map.put("黄海波","高圆圆");
        map.put("文章","马伊琍");
        //方式一:Set<K> keySet():获取所有的键值
       /* Set<String> strings = map.keySet();
        for(String str:strings){
            String s = map.get(str);
            System.out.println(str+"\t"+s);
        }*/
       //方式二:Set<Map.Entry<K,V>> entrySet():获取所有键值对的对象
        Set<Map.Entry<String, String>> entries = map.entrySet();
        for(Map.Entry<String,String> en:entries){
            String key = en.getKey();
            String value = en.getValue();
            System.out.println(key+"\t"+value);
        }
    }
}
6.2 HashSet集合嵌套ArrayList集合?
6.3 模拟斗地主的洗牌和发牌,保证牌的有序
public class PokerTest1 {
    public static void main(String[] args) {
        TreeMap<Integer,String> tm = new TreeMap<>();//创建牌库
        ArrayList<Integer> array = new ArrayList<>();
        int index = 0 ;
        String[] colors = {"♥","♠","♣","♦"} ;
        String[] numbers = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
        for(String color:colors){//装牌
            for (String number:numbers){
                String poker = color.concat(number);
                tm.put(index,poker);
                array.add(index);
                index++;
            }
        }
        tm.put(index,"小王");
        array.add(index);
        index++;
        tm.put(index,"大王");
        array.add(index);
        Collections.shuffle(array);
        TreeSet<Integer> player1 = new TreeSet<>() ;//创建玩家对象
        TreeSet<Integer> player2 = new TreeSet<>() ;
        TreeSet<Integer> player3 = new TreeSet<>() ;
        TreeSet<Integer> diPai  = new TreeSet<>() ;
        for(int x=0 ; x<array.size();x++){
            if(x >= array.size()-3){
                //底牌
                diPai.add(array.get(x)) ;
            }else if(x % 3 == 0){
                //玩家1
                player1.add(array.get(x)) ;
            }else if(x %3 ==1){
                //玩家2
                player2.add(array.get(x)) ;
            }else if(x % 3==2){
                //玩家3
                player3.add(array.get(x)) ;
            }
        }
        lookPoker("高圆圆",player1,tm) ;
        lookPoker("赵又廷",player2,tm) ;
        lookPoker("张杨",player3,tm) ;
        lookPoker("底牌",diPai,tm) ;
    }
    public static  void lookPoker(String name,TreeSet<Integer> s,TreeMap<Integer,String>
            tm){
        System.out.println(name+"的牌是:");
        for(Integer in:s){
            String s1 = tm.get(in);
            System.out.print(s1+"  ");
        }
        System.out.println();
    }
}
6.4 模拟斗地主的洗牌和发牌,牌无序
public class PokerTest {
    public static void main(String[] args) {
        ArrayList<String> arrays = new ArrayList<>();//装牌,创建ArrayList集合
        String[] colors = {"♠","♣","♦","♥"};		//定义花色和数字数组
        String[] nums= {"A","1","2","3","4","5","6","7","8","9","10","J","Q","K"};
        for(String color:colors){
            for(String num:nums){
                String poker = color.concat(num);
                arrays.add(poker);//添加带牌库
            }
        }
        arrays.add("大王");
        arrays.add("小王");//添加带牌库
        Collections.shuffle(arrays);//随机打乱牌库
        ArrayList<String> player1 = new ArrayList<>();//创建万家
        ArrayList<String> player2 = new ArrayList<>();
        ArrayList<String> player3 = new ArrayList<>();
        ArrayList<String> dipai = new ArrayList<>();
        for(int x=0 ; x<arrays.size();x++){	//发牌
            if(x>=arrays.size()-3){//规律
                dipai.add(arrays.get(x));
            }else if(x%3==0){
                player1.add(arrays.get(x));
            }else if(x%3==1){
                player2.add(arrays.get(x));
            }else if(x%3==2){
                player3.add(arrays.get(x));
            }
        }
        lookPoker("王东磊",player1);
        lookPoker("张扬",player2);
        lookPoker("刘宝寿",player3);
        lookPoker("底牌",dipai);
    }
    public static void lookPoker(String name,ArrayList<String> list){	//看牌定义方法
        System.out.print(name+"的牌是:");
        for(String s:list){
            System.out.print(s+" ");
        }
        System.out.println();
    }
}
6.5 Collections工具类的使用
 public static  T max(Collection<? extends T> coll):获取Collection中的最大值
 public static <T> int binarySearch(List<? extends Comparable<? super T>> list,T key)
    二分搜索法(折半查找):查询集合中指定的元素第一次出现的索引值,(前提:集合必须有序!)
 
 //对list集合进行排序的方法
 static <T extends Comparable<? super T>> void sort(List<T> list) :自然排序
 static <T> void sort(List<T> list, Comparator<? super T> c)  :针对List集合的比较器排序
  public static void shuffle(List<?> list):随机置换
6.6 对List集合进行排序的方法
static <T extends Comparable<? super T>> void sort(List<T> list) :自然排序--T如果是自定义类型,必须实现Compareable接口,实现compareTo方法

static <T> void sort(List<T> list, Comparator<? super T> c)  :针对List集合的比较器排序
 
7.多线程引入
单线程程序:执行的执行路径只有一条
多线程程序:执行的路径有多条
什么是进程:能够调用系统资源的独立单位(官方);进程是一个具有独立功能的程序,一个实体,每一个进程都有自己的空间地址
			官方描述:线程是依赖于进程存在,一个进程可能存在多个线程
什么是线程:线程是进程中的一个执行路径,共享一个内存空间,线程之间可以自由进行切换,并发执行,一个进程最少有一个线程;
			官方描述:能够执行进程的独立的单元(一个线程相当于进程中的某个任务)
jvm是多线程的进程,至少有两条线程,用户线程main和垃圾回收线程;
7.1 多线程的创建方式1
线程类Thread类:线程是程序中执行的线程,Java虚拟机允许应用程序同时执行多个执行线程。
创建方式一:
1)自定义一个类,让这个类继承自Thread类,线程类
2)重写Thread类的run方法:一般耗时的操作(睡眠/循环操作...)
                 run方法是一个普通方法
3)在用户线程main中,创建当前自定义类对象-->线程类
4)启动线程,调用start()---->特殊方法
         交给jvm,jvm调用run方法,让多个线程并发执行
异常:IllegalThreadStateException:非法状态异常-->同一个线程被启动两次
7.1.1 java如何开启线程(面试题)
java不能直接开启线程,需要调用start方法,最终底层使用的方法是本地方法,非java语言实现的
7.1.2 线程中的方法
public final void setName(String name):设置线程名称
public final String getName():获取线程名称(在run方法中使用)
public final void join():等待这个线程死亡
                throws InterruptedException:需要抛出异常
public final void setPriority(int newPriority):设置优先级
public final int getPriority():获取优先级
public static final int MIN_PRIORITY:最小优先级
public static final int NORM_PRIORITY:默认优先级
public static final int MAX_PRIORITY:最大优先级
public static void yield():暂停当前正在执行的线程并且执行其他线程(使用这个方法的目的是让相同优先级的线程出现一种轮转运行,但是不能保证让步的目的,因为可能一个线程在让步的同时,被另一个线程抢占了执行权)
public static void sleep(long millis):使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),
   throws InterruptedException(只能使用try/catch方法抛出异常)
7.1.3 sleep和wait()方法的区别(面试题)
1)来源不同
thread()---来自Thread类
wait():需要唤醒---来自object类,跟所对象有关,而锁对象又是任意的java类对象
2)是否会释放锁
thread直接调用sleep()方法,睡眠时间到了,就继续执行线程,他只是一个普通方法,不会释放锁
wait():是需要被锁对象调用的,调用的时候,会立即释放锁
2)都有抛出异常--->中断异常(打破当前的异常状态)
7.2 多线程的意义
多个线程在互相抢占CPU执行权,提高抢占CPU的执行权
	线程的执行具有随机性.
7.3 通过电影院的3个窗口同时出售100多张票,引入多线程安全问题(重点)
public class SellTicket implements  Runnable {
    //100张票
    private static int tickets = 100 ;
    @Override
    public void run() {
        //模拟一直有票 while循环
        while(true){
            if(tickets>0){
                //为了模拟真实场景,加入延迟操作,睡眠100毫秒
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }             System.out.println(Thread.currentThread().getName()+"正在出售第"+(tickets--)+"张票");
            }
        }
    }
}

7.3.1 静态代理模式
定义:代理模式的一种,描述一种思想"让别人帮助我们完成一些事情"
创建型:对象的创建,
    列举:简单工厂(静态工厂方法模式),工厂模式,单例模式等等...
结构型:整个部分的组成(有什么样的类,类是具体类还是抽象类,接口等等);
	 代理模式
        动态代理:
			反射里面----jdk动态代理(本身jdk提供的实现)
 			Spring ---->cglib动态代理(提供第三方jar包)
		 静态代理
行为型:根据相关的功能
静态代理:
    静态代理最大的特点:代理角色和真实角色需要完成实现同一个接口
     	代理角色;帮助真实完成一件事情
     	真实角色:专注于自己的主要的事情
//结婚的接口
public interface marry {
    void marry();
}
//真实角色的实现类
public class You implements marry{
    @Override
    public void marry() {
        System.out.println("我要结婚了");
    }
}
//代理角色类
public class MarryCompany implements marry {
    private marry marry;
    public MarryCompany(marry marry){
        this.marry=marry;
    }
    @Override
    public void marry() {
        System.out.println("婚庆公司布置婚礼现场");
        marry.marry();
        System.out.println("婚庆公司收尾款");
    }
}
//测试类
public class MarryTest {
    public static void main(String[] args) {
        //1)创建真实角色对象
        marry m = new You();
        //2)创建代理角色对象
        MarryCompany mc = new MarryCompany(m);
        mc.marry();
    }
}

7.3.2龟兔赛跑(共用一个跑道,结果是乌龟赢)
public class Race implements Runnable {
    //定义一个成员变量
    private static String winner ;//定义一个胜利者
    @Override
    public void run() {
        //兔子和乌龟都需要执行这个
        //for循环中,定义一个赛道举例
        for(int x = 0 ; x<=100; x ++){//0-99步数
            //如果当前线程名称如果是兔子的话,需要让它睡觉,不要睡眠太长
            //同时每10步 睡觉
            if(Thread.currentThread().getName().equals("兔子")&& x==90){
                //睡眠 10毫秒
                //public static void sleep(long millis)
                // throws InterruptedException
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //判断比赛是否结束
            //调用功能
            boolean flag = gameOver(x) ;//x步数
            if(flag){
                break;
            }
            //输出各跑了多少步
            //正在运行的那个线程的名称跑了 x步
            System.out.println(Thread.currentThread().getName()+
                    "--->跑了"+x+"步");
        }
    }
    //定义了一个方法,判断是否完成比赛
    private boolean gameOver(int stpes) {//步数
        //判断是否存在胜利者
        if(winner!=null){
            //存在胜利者
            return  true ;
        }else{
            //在判断如果部署>=100,比赛也要结束
            if(stpes >=100){
                //获取胜利者,线程的名称
                winner = Thread.currentThread().getName() ;
                //打印出胜利者
                System.out.println("胜利者是-->"+winner) ;
                return true ;
            }
        }
        return  false ;
    }
    //为了方便,不直接去定义测试类
    public static void main(String[] args) {
        //创建资源类对象
        Race race = new Race() ;
        //创建两个线程,分别是兔子和乌龟
        new Thread(race,"兔子").start();
        new Thread(race,"乌龟").start();
    }
}

7.4 多线程的创建方式2(推荐)----“数据共享”–较于方式1的优点
较于方式一的优点:1)方式2实现的是一个接口,面向接口编程,提供扩展性,就具备run方法去完成我们的业务逻辑,2)方式1是继承关系,具有局限性
2)从内存角度考虑:能体现出多个线程共享同一个内存空间,创建接口Runnable的子实现类,然后多个线程同时操作同一个资源类对象;
3)方式2使用到静态代理模式;
步骤:
 1)自定义一个类(资源共享类)实现Runnable接口,重写run方法-->耗时的操作
 2)在main线程,创建资源类对象
 3)创建Thread类=->线程对象,将资源类对象作为参数传递
       public Thread(Runnable target,String name)
       资源类被多个线程共用!
 4)启动线程

7.5 如何解决线程安全问题?
通票出现的原因是因为线程的原子性,++或者--是最简单的
负票出现的原因是因为线程的随机性
校验多线程的标准是什么?
	1)是都存在多线程环境
	2)是否存在共享数据
	3)是否有多条语句对共享数据进行操作
如何解决标准中的标准?
	1)标准1和2无法优化
	2)针对标准3进行解决---使用java的技术"同步机制"
		使用同步代码块将标准3对共享数据进行操作的多条语句包裹起来
锁对象:是任意的java类对象,包括自定义/jdk提供的类,且必须保证多个线程使用的所对象必须是"同一个锁对象"
synchronized(任意java类对象)--:悲观锁,也叫独占锁		

7.5 线程的生命周期和线程的状态
线程生命周期大体分为:1)新建状态 NEW
			2)就绪状态:说明有抢占CPU的资格了
			3)运行状态:抢占到CPU的执行权
			4)线程终止:CPU运行结束
线程的状态有六种--->内部枚举类型:State状态
	NEW:新建状态
	Runable:运行状态
	Bolcked:阻塞状态
	Waiting:死死等待:类似于join()方法--底层依赖于wait(0)
	Timed_Waiting:超时等待-->wait(long time具体毫秒值)
	Terminated:终止状态--线程执行完毕的状态
	

7.6 什么叫同步方法
如果一个方法中,一进来就是同步代码块,就可以将synchronized关键字提到方法声明上,这样的方法叫"同步方法"
同步方法中的同步代码块是有锁对象的,同步方法的锁对象就是this;
静态同步方法的锁对象是类的字节码文件--->类名.class

7.7 LOCK接口—具体的锁定操作
void lock:获得锁
void unlock:释放锁
 jdk5以后可以直接使用接口Lock--->子实现类:可重入互锁:ReentrantLock
  Lock l = new ReentrantLock; //创建了锁
           try {
				l.lock;	//上锁
              // 同步代码快
           } finally { //释放资源
                l.unlock(); //释放锁
             }

7.7 同步机制解决安全—可能会引起死锁
死锁:当前多个线程操作不是一个子类对象,可能造成线程出现互相等待的情况!
如何解决线程死锁:就是使用生产者和消费者模式思想

8. 生产者消费者模式–引入java中的等待唤醒机制(信号灯法或者管线程法)
1.模拟生产者消费者思想模式
SetThread类---->生成者所在的线程的资源类
getThread类---->消费者所在线程的资源类
Student类---->生成者线程不断的去产生学生数据,消费者线程不断去使用学生的数据
StuduentTest类--->主线程(main用户线程--->等会创建资源类以及对应的线程,模拟生成和消费的场景)

如何消除死锁:唤醒机制(信号灯法)
资源类对象.notify() ;

9.引入线程池的方式创建线程
定义:线程池,thread pool,是一种线程使用模式,线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。”
线程池的优点:使用相关的工厂类(jdk提供得Executors)创建一些固定的可重用线程的数量,然后当前线程使用完毕的时候,他不会被垃圾回收掉,而将线程归还到线程池中,等到下一次去利用它,"变废为宝";
线程池的弊端:维护成本非常高

9.1 使用步骤
Jdk提供了一个工厂类:Executors
1) public static ExecutorService newFixedThreadPool(int nThreads):建一个线程池,该线程池重用固定数量的线程
2) <T> Future<T> submit(Callable<T> task)提交异步任务计算的结果
		返回值:Future是接口:异步任务计算的结果
		V get():获取返回值计算结果(需要抛出异常)
		方法的形参:是一个接口Callable--->call方法:计算结果,本身带了throws Exception{}
3)void shutdown():启动有序关闭,先执行的线程,就按照顺序关闭(关闭线程池)
public class ThreadPoolDemo {
public static void main(String[] args) {
        //创建线程池对象Executors调用静态方法
    ExecutorService threadPool = Executors.newFixedThreadPool(2);//创建了2个固定的线程数量,返回值就是线程池接口
        //现在不计算异步任务执行的结果,返回值可以不写Future
        //<T> Future<T> submit(Callable<T> task)
        threadPool.submit(new MyCallable()) ;//提交一个线程操作
        threadPool.submit(new MyCallable()) ;//提交另一个线程操作

        //关闭线程池
        threadPool.shutdown();
    }
}
public class MyCallable implements Callable {
    //Callable<V>泛型的类型和call返回的类型一致
    @Override
    public Object call() throws Exception {
        for(int x = 0  ; x <100 ;x ++){
            System.out.println(Thread.currentThread().getName()+":"+x);
        }
        return null;
    }
}

9.2 线程池中相关的参数–了解有关的7大参数

10.定时器–java.util.Timer(了解)
java.util.Timer:使用定时器可以完成定时任务,任务可以安排一次执行,或定期重复执行;
构造方法:无参构造方法 time();---创建一个新的定时器

10.1 java的常用设计原则(*为记住)
*单一职责原则:也成为了低耦合,高内聚;java的23中设计原则都遵循这一原则
*开闭原则:一个对象对扩展开放,对修改关闭
意思是对类的改动是通过增加代码进行的,而不是修改现有代码
里氏替换原则:核心思想:在任何父类出现的地方都可以用它的子类替代
			也就是说:同一个继承体系中的对象应该由共同的行为特征;
依赖注入原则:核心思想:要依赖于抽象,不要依赖于具体实现
		也就是说,在应用程序中,所有的类使用或者依赖其他的类,则应该依赖于这些类的抽象类
*接口分离原则:开发中,面向接口编程,而一个接口中,不应该将所有的操作都放在一个接口中,肯定要分离模块,开发中,先按模块划分,再按功能划分


10.2 常见的设计模式–工厂模式和单例模式
设计模式不是一种方法和技术,是一种思想;
创建型模式:对象的创建;
结构式模式:对象的组成(结构)
行为性模式:对象的行为
创建型模式:1)简单工厂模式---静态工厂方法模式
	核心思想:定义一个具体的工厂类负责创建一些类的实例
	优点:客户端不负责对象的创建,都是有工厂类进行创建;从而明确了各个类的职责
	弊端:有新的类型增加,工厂类的代码就得修改,不利于后期的维护;
2)工厂方法模式:
	核心思想:抽象工厂类可以负责定义创建对象的接口,具体的对象的创建工作由继承抽象工作的具体类实现;
	优点:每个类都有对应的工厂类负责该实例的创建,维护方便
	缺点:一旦有新的类型增加,还得需要提供对应的工厂类,代码量增大
3)单例模式
	核心:在内存中始终保证只有一个该类对象的实例,而且对外提供
	单例模式分为两种:	饿汉式:不会出现问题的单例模式
     				 懒汉式:可能出现(线程的安全问题)问题的一种单例
     	实际面试中,问的比较多的是懒汉式,因为饿汉式是永远不会出现问题的一种单例模式!
  饿汉式: 1)保证当前内存中始终只有一个该类实例
     2)在当前类的成员位置:声明一个私有的静态的实例变量
     3)提供一个静态方法对外的成员方法,返回值是实例变量--始终在内存中只有一个实例
     饿汉式:不会出现问题的单例模式
  懒汉式:可能出现问题的单例模式,它不是类一加载就直接创建当前类实例,而是需要判断,用的时候,才创建实例!当前存在延迟加载或者懒加载的时候类似于一种多线程环境了,就会出现线程安全问题,解决办法就是加锁,使用同步方法
     

10.2.1 饿汉式单例模式
饿汉式:不会出现问题的单例模式
特点:1)当前类的无参构造方法私有化,外界不能new;
2)在当前类的成员位置,创建一个当前类对象,被静态修饰并且私有化
3)对外提供公共的静态功能,返回值当前类本身
Class Student{
    private static Student s = new Student;
    private Student(){};
    public static Student getStudent(){
        return s;
    }
}
class studenttest{
    public static void main(String[] args){
       Student s1 = Student.getStudent();
       Student s2 = Student.getStudent();
       System.out.println(s1==s2);//结果为ture
    }
}

10.2.2 懒汉式单例模式
 懒汉式:可能出现问题的单例模式,它不是类一加载就直接创建当前类实例,而是需要判断,用的时候,才创建实例!当前存在延迟加载或者懒加载的时候类似于一种多线程环境了,就会出现线程安全问题,解决办法就是加锁,使用同步方法
Class Teather{
    private static Teather t ;
    public synchronized static Teather getTeather(){
    //锁对象就是Teacher.class;
        if(t == null){
            t = new Teather();
            return t;
        }else{
            return t;
        }
    }
}

11. IO流的分类(input and outprint)
11.1 File类的认识和方法
File()类:文件和目录(文件夹)的抽象路径形式
构造方法:File(String pathname)(推荐)
	例如File file = new File("E:\\demo\\a.txt")
File的基本方法:
	public boolean createNewFile() throws IOException:创建文件
	public boolean mkdir():创建目录,如果不存在,则创建,否则返回false;
	public boolean mkdirs():创建多个目录,如果父目录不存在,自动创建父类以及里面的子目录	
	public boolean delete():可以删除文件或者文件夹,删除文件夹的时候,注意,如果目录为空,才能删除!
		绝对路径:带盘符的具体路径:在指定的目录中 创建文件或者文件夹
 		相对路径:如果不带盘符:在当前项目下的路径下创建文件或者目录
 判断功能:
	public boolean exists():file所表示的路径是否存在
	public boolean isFile():是否是文件
	public boolean isDirectory():是否是目录
	public long length():获取长度


11.2 流的分类
按流的方向划分:
	1)输入流
	2)输出流
按流的类型划分:
	1)字节流:先出现的
	2)字符流:后出现的
先按流的类型划分,再按流的方向划分
	字节输入流---抽象类--InputStream
	字节输出流----OutputStream
	字符输入流---Reader
	字符输出流---Write

11.3. 字节输出流(OutputStream)的写数据的方式
OutputStream是抽象类,是所有的字节输出流的超类,常用的子实现类: Clss FileOutputStream
1)创建字节输出流对象--操作文件--属于底层语言调用系统资源的操作(非java语言实现)
	public FileOutputStream(String name)throws FileNotFoundException:创建输出流对象
2)写数据
	public void write(byte[] b,int off,int len) throws IOException:写字节数组的一部分:参数1:字节数组 参数2:指定某个位置, 参数3:指定长度
3)释放资源---流对象.colse();释放流对象指向的文件的空间地址值
 windows系统中的换行符号 "\r\n"
 Linux系统中"\n"
 FileOutputStream的构造方法(1):public FileOutputStream(String name) throws FileNotFoundException
 构造方法(2):public FileOutputStream(String name,boolean append)throws FileNotFoundException:在末尾追加内容,将上一次内容记录下来,直接后面直接追加!
 将字符串转换为字节:"字符串".getbytes();
 
public class OutputStreamDemo {
    public static void main(String[] args) throws IOException {
        //1)创建输出流对象,输入到指定文件中
        OutputStream os = new FileOutputStream("fos.txt");
        //2)写数据
        byte[] bytes ={97,98,99,100};
        os.write(bytes);
        os.close();
    }
}
11.4 字节输入流读取数据的方式
public class InputStreamDemo {
    public static void main(String[] args) throws Exception {
    //创建字节输入流对象
        InputStream is = new FileInputStream("OutputStreamDemo.java");
//创建数组的时候,一般长度是1024或者1024的整数倍,一般1024足够用了
        byte[] bytes = new byte[1024];
        int len = 0;//从0开始
        while((len=is.read(bytes))!=-1){
            String string = new String(bytes,0,len);
            System.out.println(string);
        }
    }
}

11.5 实际操作:针对文本文件,图片文件,音频文件,进行读写
public class InputStreamDemo {
    public static void main(String[] args) throws Exception {
        InputStream is = new FileInputStream("OutputStreamDemo.java");
        OutputStream os = new FileOutputStream("fos2.java");
        byte[] bytes = new byte[1024];
        int len = 0;
        while((len=is.read(bytes))!=-1){
        //将输入流的内容读取出来并且写进输出流对象中
            os.write(bytes,0,len);
        }
    }
}

11.6.1 使用字节缓冲输入流和输出流读写复制—使用缓冲区使读写更高效
public class copyTest {
    public static void main(String[] args) throws IOException {
        BufferedOutputStream bos=
                new BufferedOutputStream(new FileOutputStream("copy.java"));
        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
                "fos4.java"));
        byte[] bytes = new byte[1024];
        int len = 0 ;
        while((len = bis.read(bytes))!=-1){
            bos.write(bytes,0,len);
            bos.flush();
        }
        bos.close();
        bis.close();
}}
11.6 引入字符流–字符输入流,字符输出流
抽象类
Reader:字符输入流--子实现类FileReader
writer:字符输出流--子实现类FileWriter
写的功能:
    public void write(char[] cbuf) throws IOException:写一个字符数组
     public abstract void write(char[] cbuf,int off,int len) throws IOException:从指定位置开始写入一部分字符数组
     public void write(String str)throws IOException:写入字符串
     public void write(String str,int off,int len)throws IOException :写字符串的一部分
     public void write(int c) throws IOException写一个字符
    	public class WriteReadDemo {
    public static void main(String[] args) throws IOException {
        //创建字符输入流对象
        FileWriter w = new FileWriter("fos4.java");
        //创建字符输出流对象
        FileReader fw = new FileReader("fos2.java");
        char[] cha = new char[1024];
        int len = 0 ;
        while((len = fw.read(cha))!=-1){
            w.write(cha,0,len);
        }
        w.close();
        fw.close();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值