Java基础知识点汇总
- 一. Java基础语法
 - 
- 1. 类型转换
 - 2. 方法
 - 3. 位运算
 - 4. 循环
 - 5. 装箱与拆箱
 - 6. 内存分析
 
 - 二. 面向对象
 - 
- 1. 概念
 - 2. 对象的初始化与创建
 - 3. 创建对象的内存分析
 - 4. 封装
 - 5. 继承
 - 6. 多态
 - 7. Instanceof
 - 8. Static关键字、代码块
 - 9. 抽象类
 - 10. 接口
 - 11. 方法的重写和重载
 
 - 三. 异常处理
 - 四. 集合
 - 
- 1. 集合的概念
 - 2. Collection体系
 - 3. Collection中常用方法
 - 4. Iterator迭代器
 - 5. Contains方法
 - 6. 集合转数组
 - 7. Remove方法
 - 8. List集合
 - 9. 泛型
 - 10. HashSet集合
 - 11. TreeSet集合
 - 12. Map接口常用方法
 - 13. Map的遍历
 - 14. HashMap
 - 15. HashTable集合
 - 16. Properties集合
 - 17. TreeSet集合元素排序
 - 18. 自平衡二叉树
 - 19. Collections工具类
 
 - 五. IO流
 - 
- 1. 什么是IO
 - 2. IO流的分类
 - 3. IO流四大家族
 - 4. FileInputStream和FileOutputStream
 - 5. FileReader和FileWriter
 - 6. 文件拷贝
 - 7. BufferedReader和BufferedWriter
 - 8. PrintStream
 
 - 六. 注解
 - 七. 反射
 - 
- 1. Class类
 - 2. Class类的实例
 - 3. Class类的创建方式
 - 4. 类加载器
 - 5. 获取类运行时完整结构
 - 6. 动态创建对象调用方法和属性
 
 - 八. 多线程
 - 
- 1. 概念
 - 2. 创建线程的三种方式
 - 3. 静态代理
 - 4. Lambda表达式
 - 5. 停止线程
 - 6. 线程休眠
 - 7. 线程礼让
 - 8. 线程强制执行
 - 9. 线程状态
 - 10. 线程优先级
 - 11. 守护线程
 - 12. 线程同步机制
 - 13. 死锁
 - 14. Lock(锁)
 - 15. 线程池
 - 16. wait和notify
 - 17. 生产者消费者
 
 
一. Java基础语法
1. 类型转换
        // 强制类型转换
        float a = 20.34f;
        int b = (int)a;
        //自动类型转换
        int c = 10;
        float d = c;
        //操作较大的数时,注意溢出问题
        //JDK7新特性,数字之间可以用下划线分割
        int money = 10_0000_0000;
        int years = 20;
        long total = money * years;//默认两个参数都是int,计算的时候产生溢出
        System.out.println(total);//-1474836480
        long total_2 = money*((long)years);//先把一个数转化为long
        System.out.println(total_2);//20000000000
2. 方法
    public static void main(String[] args) {
        // 可变参数的传递
        Demo01 demo = new Demo01();
        demo.printMax(2,485,1,2,344,5);
    }
    public void printMax(int ...numbers){ //仅能为最后一个参数才能使用...}
3. 位运算
       //位运算
        /*
        * A = 0011 1100
        * B = 0000 1101
        * --------------
        * A & B = 0000 1100       对应位置都为1才为1
        * A | B = 0011 1101       对应位置有一个为1,结果为1
        * A ^ B = 0011 0001       对应位置相同为0,不同为1
        * ~ B = 1111 0010         对应位置取反
        *
        *
        * 2 * 8 =16,  2*2*2*2
        * << 左移  *2
        * >> 右移  /2
        *
        * 0000 0000   0
        * 0000 0001   1
        * 0000 0010   2
        * 0000 0011   3
        * 0000 0100   4
        * 0000 1000   8
        * 0001 0000   16
        *
        * */
4. 循环
        //增强for循环
        int[] numbers = {10,20,30,40};
        for (int x:numbers){
            System.out.println(x);
        }
5. 装箱与拆箱

6. 内存分析

二. 面向对象
1. 概念
面向对象的本质:以类的方式组织代码,以对象的方式封装数据。
 三大特性:封装,继承,多态。
2. 对象的初始化与创建
使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及对类中的构造器的调用。一旦定义了有参构造,无参构造就必须要显示定义。
3. 创建对象的内存分析

4. 封装
程序设计的要求:“高内聚,低耦合”。高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合:仅暴露少量的方法给外部使用。
 封装(数据的隐藏):应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问。
5. 继承
所有的类都默认直接或者间接继承Object类。JAVA中类只有单继承,无多继承。私有的东西无法被类继承。
6. 多态
多态存在的条件:① 有继承关系。② 子类重写父类的方法。③ 父类引用指向子类对象。④ 多态是方法的多态,属性没有多态。⑤ 对象能够执行的方法,主要看左边的类型。当子类重写了父类的方法,所调用的皆是子类的方法。
7. Instanceof
Java 中的instanceof 运算符是用来在运行时指出对象是否是特定类的一个实例。instanceof通过返回一个布尔值来指出,这个对象是否是这个特定类或者是它的子类的一个实例。
8. Static关键字、代码块
Static关键字:和类一起加载,可以直接通过 (类名.静态方法) 调用方法。
 代码块:执行顺序:静态代码块 > 构造方法 > 匿名代码块。静态代码块只执行一次,即使有多个同一个类的实例,仍只运行一次。
9. 抽象类
① 抽象方法,只有方法的名字,没有方法的实现。② 不能new抽象类,只能靠子类来实现。③ 抽象方法必须在抽象类中,抽象类中可以有普通方法。 ③ 抽象类的所有方法,都需要由它的子类来实现。 除非子类为抽象类,则由子子类实现。
10. 接口
① Interface 定义的关键字,接口都需要有实现类。② 接口中所有方法都是抽象的:public abstract,接口只可做方法的声明。 ③ 类实现接口需要重写接口中的所有方法。④ 利用接口可以实现多继承。
11. 方法的重写和重载
- 
方法的重写
① 需要有继承关系,子类重写父类的方法,与属性无关。
② 方法名相同,参数列表必须相同,方法体不同。
③ 修饰符范围可以扩大但不能缩小:public>protected>default>private。
④ 抛出的异常范围可以缩小但不能扩大。
⑤ 重写的原因:父类的功能,子类可能不需要或不满足。 - 
方法的重载
① 重载就是在同一个类中,有相同的函数名称,但形参不同的函数。
② 方法名必须相同,参数列表必须不同(参数个数不同,或类型不同,或参数排列顺序不同等)
③ 方法的返回类型可以相同也可以不同。
④ 仅仅返回类型不同不足以构成方法的重载。 
三. 异常处理
- 异常两大类:Exception、Error。

 - 若多个catch捕获异常,异常等级由小到大。 Finally可以不要,一定会执行,用于处理善后工作。
 - 自定义异常类:类继承Exception。Throw new MyException():抛出自定义异常。
 
四. 集合
1. 集合的概念
① 集合是对象的容器。
 ② 集合不能直接存储基本数据类型,集合也不能直接存储java对象,集合当中存储的都是java对象的内存地址。(或者说集合中存储的是引用)
 ③ 集合类和集合接口都在java.util.* 包下。
 ④ 数组可存储基本类型和引用类型,集合只能存储引用类型。
 
2. Collection体系

 
3. Collection中常用方法

4. Iterator迭代器

 
 
 public static void main(String[] args) {
        //以下遍历方式/迭代方式,是所有collection通用的一种方式。 在Map集合中不能使用。
        //创建集合对象
        Collection c = new ArrayList();//后面的集合无所谓,主要是看前面的collection接口,怎么遍历/迭代。
        //添加元素
        c.add(120);
        c.add("hello");
        c.add(new Object());
        //对集合Collection进行遍历/迭代
        //第一步:获取集合对象的迭代器对象Iterator
        Iterator it = c.iterator();
        //第二步:通过上步获得的迭代器进行遍历
        /*
        * 迭代器对象iterator中的方法:
        * boolean hasNext(); 如果仍有元素可以迭代,返回true。
        * Object next(); 返回迭代的下一个元素。Object obj = it.next();
        * */
        System.out.println("集合中元素有:");
        while(it.hasNext()){
            Object o = it.next();
            System.out.println(o);
        }
    }
5. Contains方法


 
6. 集合转数组

7. Remove方法

8. List集合

 
 
9. 泛型

 
 
 

 
10. HashSet集合

11. TreeSet集合

12. Map接口常用方法

 
 
13. Map的遍历

 
 
14. HashMap

 
 
 
 
 
15. HashTable集合

16. Properties集合

 
17. TreeSet集合元素排序
方法一:类实现Comparable接口,重写compareTo方法。
//自定义类型实现comparable接口,放在TreeSet集合后实现排序。
//放在TreeSet集合中的元素需要实现java.lang.Comparable接口。
//并且实现compareTo方法,equals方法可以不写。
class Customer implements Comparable<Customer>{
    int age;
    public Customer(int age) {
        this.age = age;
    }
    //需要在这个方法中实现比较的逻辑或规则,有程序员指定。
    @Override
    public int compareTo(Customer o) {
        return this.age - o.age;//比较年龄大小
    }
    @Override
    public String toString() {
        return "Customer{" +
                "age=" + age +
                '}';
    }
}
方法二:编写一个类,实现Comparator接口,重写compare方法。
//给构造方法传递一个比较器
TreeSet<WuGui> wuGuis = new TreeSet<>(new WuGuiComparator());
//单独写一个比较器,实现java.util.Comparator接口。
//而Comparable是Java.lang包下的。
class WuGuiComparator implements Comparator<WuGui> {
    @Override
    public int compare(WuGui o1, WuGui o2) {
        return o1.age - o2.age;
    }
}
class WuGui{
    int age;
    public WuGui(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "WuGui{" +
                "age=" + age +
                '}';
    }
}
方式三:匿名内部类,不单独写构造器。
 
//第三种方式使用匿名内部类,不用单独写构造器,直接new接口
TreeSet<WuGui> wuGuis = new TreeSet<>(new Comparator<WuGui>() {
	  @Override
	  public int compare(WuGui o1, WuGui o2) {
	     return o1.age - o2.age;
	  }
});

18. 自平衡二叉树

19. Collections工具类

 
 ① HashSet输出的元素是无序的(存储自定义类型元素,需重写equals和hashcode方法,避免重复的问题),TreeSet输出的元素自动排序(实现接口,编写比较器)。
 ② HashMap中元素是没有顺序的;TreeMap中所有元素都是有某一固定顺序的。
五. IO流
1. 什么是IO

2. IO流的分类

3. IO流四大家族

 
4. FileInputStream和FileOutputStream
public class FileInputStreamTest03 {
    public static void main(String[] args) {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream("tempfile");
            byte[] bytes = new byte[4];
            int readCount = 0;
            while ((readCount = fis.read(bytes)) != -1){
                System.out.print(new String(bytes,0,readCount));
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  public static void main(String[] args) {
        FileOutputStream fos = null;
        try {
            //文件不存在会自动新建
            //该语句执行时,会先清空文件内容,然后再写
//            fos = new FileOutputStream("testfile.txt");
            //以追加的方式在文件末尾写,不清空源文件
            fos = new FileOutputStream("testfile.txt",true);
            //开始写
            byte[] bytes = {97,98,99,100};
            //将byte数组全部写出
            fos.write(bytes); //abcd
            //将byte数组部分写出
            fos.write(bytes,0,2);//abcdab
            String s = "我是中国人";
            //将字符串转化为字符数组
            byte[] bs = s.getBytes();
            fos.write(bs);//abcdab我是中国人
            //输出流最后要刷新
            fos.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
5. FileReader和FileWriter
   public static void main(String[] args) {
        FileReader reader = null;
        try {
            //创建文件字符流
            reader = new FileReader("tempfile");
            //开始读
            char[] chars = new char[4];
            //往char数组读
            reader.read(chars);
            for(char c : chars){
                System.out.print(c);
            }
/*            int readCount = 0;
            while((readCount = reader.read(chars)) != -1){
                System.out.print(new String(chars,0,readCount));
            }*/
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
 public static void main(String[] args) {
        FileWriter out = null;
        try {
//            out = new FileWriter("myfile.txt");
            out = new FileWriter("myfile.txt",true);
            char[] chars = {'我','是','中','国','人'};
            out.write(chars);
            out.write(chars,0,2);
            out.write("java工程师");
            out.write("\n");
            out.write("你好");
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
6. 文件拷贝
    public static void main(String[] args) {
        FileInputStream fis = null;
        FileOutputStream fos = null;
        try {
            fis = new FileInputStream("E:\\PPT模板\\An Improved DV-Hop Localization Algorithm Based on Selected Anchors.pdf");
            fos = new FileOutputStream("E:\\An Improved DV-Hop Localization Algorithm Based on Selected Anchors.pdf");
            byte[] bytes = new byte[1024*1024]; //每次最多读取1M
            int readCount = 0;
            while((readCount = fis.read(bytes)) != -1){
                fos.write(bytes,0,readCount);
            }
            //刷新
            fos.flush();
            //fos和fis关闭时,分开try。否则会影响另一个。
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //fos和fis关闭时,分开try。否则会影响另一个。
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
 public static void main(String[] args) {
        FileReader fr = null;
        FileWriter fw = null;
        try {
            fr = new FileReader("javase/src/com/IOStream/FileReaderTest01.java");
            fw = new FileWriter("fileReaderText.txt");
            char[] chars = new char[1024*512];
            int readCount = 0;
            while ((readCount = fr.read(chars)) != -1){
                fw.write(chars,0,readCount);
            }
            fw.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (fw != null) {
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fr != null) {
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
7. BufferedReader和BufferedWriter
 public static void main(String[] args) throws Exception{
        //当一个流的构造方法中需要一个流时,被传进来的流称为节点流
        //外部负责包装的这个流叫包装流或处理流
        FileReader reader = new FileReader("fileReaderText.txt");//节点流
        BufferedReader br = new BufferedReader(reader);//包装流
        //读行
        String s = null;
        while ((s = br.readLine()) != null){//读一行文本,不读换行符
            System.out.println(s);
        }
        br.close();//关闭包装流自动关闭节点流
    }
    public static void main(String[] args) throws Exception{
        //字节流
        FileInputStream in = new FileInputStream("fileReaderText.txt");
        //字节流转化为字符流
        InputStreamReader reader = new InputStreamReader(in);
        //BufferedReader构造器只能传字符流
        BufferedReader br = new BufferedReader(reader);
//        //以上合并写法:
//        BufferedReader br = new BufferedReader(new InputStreamReader
//                (new FileInputStream("fileReaderText.txt")));
        
        String s = null;
        while ((s = br.readLine()) != null){
            System.out.println(s);
        }
        br.close();
    }
    public static void main(String[] args) throws Exception{
//        BufferedWriter bw = new BufferedWriter(new FileWriter("copy.txt"));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter
                (new FileOutputStream("copy.txt",true)));//追加
        bw.write("hello");bw.write("\n");
        bw.write("houshuaixin");
        bw.flush();bw.close();
    }
8. PrintStream
    public static void main(String[] args) throws FileNotFoundException {
        //java.io.PrintStream:标准的字节输入流,默认输出至控制台
        //分开写,标准输出流不需要close()关闭
        PrintStream ps = System.out;
        ps.println("hello");ps.println("better");
        //联合写
        System.out.println("helloword");
        //改变标准输出流的输出方向
        //标准输出流不在指向控制台,指向“log”文件
        PrintStream printStream = new PrintStream(new FileOutputStream("log.txt"));
        //修改输出方向至“log.txt”文件
        System.setOut(printStream);
        System.out.println("helloword");
        System.out.println("hellokitty");
    }
六. 注解
//测试元注解
@MyAnnotation
public class TestAnnotation01 {
    public void test(){
    }
}
//定义一个注解
//Target 表示我们的注解可以用在那些地方
@Target(value = {ElementType.METHOD,ElementType.TYPE})
//Retention 表示我们的注解在什么地方还有效
// runtime>class>source
@Retention(value = RetentionPolicy.RUNTIME)
//Documented 表示是否将我们的注解生成在JAVAdoc中
@Documented
//Inherited 子类可以继承父类的注解
@Inherited
@interface MyAnnotation{
}
使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口。
//自定义注解
public class TestAnnotation02 {
    //注解可以显式赋值,如果没有默认值,必须给注解赋值。
    @MyAnnotation2(name = "hou")
    public void test(){}
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
    //注解的参数:参数类型 + 参数名 + ();
    String name();
    //String name() default "";
    int age() default 15;
    String[] schools() default {"北大","清华"};
}
七. 反射
1. Class类
① Class本身也是一个类,Class对象只能由系统建立。
 ②一个加载的类在JVM中只会有一个Class实例(Class对象只有一个)。
 ③ 一个Class对象对应的是一个加载到JVM中的一个 .class 文件。
 ④ 通过Class实例可以获得一个类中所有被加载的结构。
2. Class类的实例
    public static void main(String[] args) throws ClassNotFoundException {
        //通过反射获取类的Class对象
        Class c1 = Class.forName("Reflections.User");
        System.out.println(c1); //class Reflections.User
        Class c2 = Class.forName("Reflections.User");
        Class c3 = Class.forName("Reflections.User");
        //一个类在内存中只有一个Class对象
        //一个类被加载后,类的整个结构都会被封装在Class对象中
        System.out.println(c1.hashCode());//21685669
        System.out.println(c2.hashCode());//21685669
        System.out.println(c3.hashCode());//21685669
    }
3. Class类的创建方式
    public static void main(String[] args) throws ClassNotFoundException {
        Person person = new Student();
        System.out.println("这个人是:"+person.name);
        //方式一:通过对象获得
        Class c1 = person.getClass();
        System.out.println(c1);//class Reflections.Student
        //方式二:forname获得
        Class c2 = Class.forName("Reflections.Student");
        System.out.println(c2);//class Reflections.Student
        //方式三:通过类名.class获得
        Class c3 = Student.class;
        System.out.println(c3);//class Reflections.Student
        //方式四:基本内置类型的包装类有一个TYPE属性
        Class c4 = Integer.TYPE;
        System.out.println(c4);//int
        //获得父类类型
        Class c5 = c1.getSuperclass();
        System.out.println(c5);//class Reflections.Person
    }
4. 类加载器
    public static void main(String[] args) throws ClassNotFoundException {
        //获取系统类加载器
        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println(systemClassLoader);
        //获取系统类加载器的父类加载器---》扩展类加载器
        ClassLoader parent = systemClassLoader.getParent();
        System.out.println(parent);
        //获取扩展类加载器的父类加载器---》根加载器(C、C++)
        ClassLoader parent1 = parent.getParent();
        System.out.println(parent1); //null
        //测试当前类是那个加载器加载的
        ClassLoader classLoader = Class.forName("Reflections.Test04").getClassLoader();
        System.out.println(classLoader);
        //测试JDK内置的类是谁加载的
        ClassLoader classLoader1 = Class.forName("java.lang.Object").getClassLoader();
        System.out.println(classLoader1);
    }
5. 获取类运行时完整结构
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class c1 = Class.forName("Reflections.User");
        //获得类的名字
        System.out.println(c1.getName());//获得包名+类名
        System.out.println(c1.getSimpleName()); //获得类名
        //获得类的属性
        System.out.println("==========获得类的属性===========");
        Field[] fields = c1.getFields(); //只能找到public属性
        fields = c1.getDeclaredFields(); //找到所有属性
        for (Field field:fields){
            System.out.println(field);
        }
        //获得指定类型的属性
        Field name = c1.getDeclaredField("name");
        System.out.println(name);
        //获得类的方法
        System.out.println("==========获得类的方法===========");
        Method[] methods = c1.getMethods(); // 获得本类及其父类的所有public方法
        methods = c1.getDeclaredMethods(); // 获得本类的所有方法
        for(Method method:methods){
            System.out.println(method);
        }
        //获得指定方法(因重载问题,需出入指定方法的参数)
        Method getName = c1.getMethod("getName", null);
        Method setName = c1.getMethod("setName", String.class);
        System.out.println(getName);
        System.out.println(setName);
        //获得类的构造器
        System.out.println("==========获得指定的构造器===========");
        Constructor[] constructors = c1.getConstructors();//本类的public
        constructors = c1.getDeclaredConstructors();//本类所有的
        //获得类的指定构造器
        Constructor deConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
        System.out.println(deConstructor);
        
    }
6. 动态创建对象调用方法和属性
    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        //获得class对象
        Class c1 = Class.forName("Reflections.User");
        //创建一个对象   (针对有无参构造器)
        User user1 = (User) c1.newInstance(); //本质是调用了类的无参构造
        System.out.println(user1);
        //通过构造器创建对象   (针对没有无参构造器)
        Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
        User user2 = (User)constructor.newInstance("hou", 45, 12);
        System.out.println(user2);
        //通过反射调用普通方法
        User user3 = (User) c1.newInstance();
        //通过反射获得一个方法
        Method setName = c1.getDeclaredMethod("setName", String.class);
        setName.invoke(user3,"hou");//invoke(对象,“传入的值”)
        System.out.println(user3.getName());
        //通过反射操作属性
        User user4 = (User)c1.newInstance();
        Field name = c1.getDeclaredField("name");
        //不能直接操作私有属性,需关闭程序的安全检测,属性(方法).setAccessible(true);
        name.setAccessible(true);
        name.set(user4,"侯帅鑫");
        System.out.println(user4.getName());
        
    }
八. 多线程
1. 概念
① 进程:是一次执行程序的过程,是系统资源分配的单位。
 ② 线程:一个进程通常包括若干个线程,一个进程中至少有一个线程,线程是CPU调度和执行的单位。
 ③ Main()为主线程,为系统的入口。
2. 创建线程的三种方式
① 自定义类继承Thread类,重写run方法,创建线程对象,调用start方法启动。
 ② 自定义类实现Runnable接口,重现run方法。
 ③ 自定义类实现Callable接口,重写call方法,需抛出异常。
public class TestThreads {
    public static void main(String[] args) {
        //方式一启动线程
        new MyThread1().start();
        //方式二启动线程
        new Thread(new MyThread2()).start();
        //方式三启动线程(了解)
        FutureTask<Integer> futureTask = new FutureTask<>(new MyThread3());
        new Thread(futureTask).start();
        Integer integer = null;
        try {
            integer = futureTask.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println(integer);
    }
}
//1.继承Thread类
class MyThread1 extends Thread{
    @Override
    public void run() {
        System.out.println("MyThread1");
    }
}
//2.实现Runnable接口
class MyThread2 implements Runnable{
    @Override
    public void run() {
        System.out.println("MyThread2");
    }
}
//3.实现Callable接口
class MyThread3 implements Callable<Integer>{
    @Override
    public Integer call() throws Exception {
        System.out.println("MyThread3");
        return 100;
    }
}
3. 静态代理
① 真实角色和代理角色都要实现同一个接口。
 ② 代理对象要代理真实角色。
 ③ 优点:代理对象可以做真实对象做不了的事,真实对象专注于做自己的事。
//静态代理
public class StaticProxy {
    public static void main(String[] args) {
        You you = new You();
        new Thread( ()-> System.out.println("我爱你")).start();
        new WeddingComp(new You()).HappyMarry();
    }
}
interface Marry{
    void HappyMarry();
}
//真是角色
class You implements Marry{
    @Override
    public void HappyMarry() {
        System.out.println("我要结婚了");
    }
}
//代理角色
class WeddingComp implements Marry{
    private Marry target;
    public WeddingComp(Marry target) {
        this.target = target;
    }
    @Override
    public void HappyMarry() {
        before();
        this.target.HappyMarry();
        after();
    }
    private void after() {
        System.out.println("收尾款");
    }
    private void before() {
        System.out.println("布置婚礼现场");
    }
}
4. Lambda表达式
public class TestLambda02 {
    public static void main(String[] args) {
        // Lambda表示简化
        ILove iLove = (int a)->{
            System.out.println("I Love You -->" + a);
        };
        //简化1.参数类型
        iLove = (a)->{
            System.out.println("I Love You -->" + a);
        };
        //简化2,简化括号
        iLove = a->{
            System.out.println("I Love You -->" + a);
        };
        //简化3,去掉花括号 ,仅适用于只有一行代码的情况
        iLove = a -> System.out.println("I Love You -->" + a);
        //前提接口为函数式接口
        //多个参数的类型名可同时省略,但括号必须保留
        iLove.love(2);
    }
}
interface ILove{  //函数式接口
    void love(int a);
}
5. 停止线程
//停止线程
//测试Stop
//1.建议线程正常停止--->利用次数,不建议死循环
//2.建议使用标志位---->设置一个标志位
//3.不要使用stop或者destroy等过时或者JDK不建议使用的方法
public class TestStop implements Runnable{
    //1.设置一个标识位
    private boolean flag = true;
    @Override
    public void run() {
        int i = 0;
        while(flag){
            System.out.println("run....." + i++);
        }
    }
    //2.设置一个公开的方法停止线程
    public void stop(){
        this.flag = false;
    }
    public static void main(String[] args) {
        TestStop testStop = new TestStop();
        new Thread(testStop).start();
        for (int i = 0; i < 1000; i++) {
            System.out.println("main--->"+i);
            if(i == 900){
                //转换标识位,停止线程
                testStop.stop();
                System.out.println("线程停止==========");
            }
        }
    }
}
6. 线程休眠
sleep时间达到后线程进入就绪状态,sleep可以模拟网络延时,倒计时等。每个对象都有一个锁,sleep不会释放锁。
//模拟倒计时
public class TestSleep {
    public static void main(String[] args) {
        //倒计时
        try {
            tenDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //打印当前系统时间
        Date startTime = new Date(System.currentTimeMillis());//获取系统当前时间
        while (true){
            try {
                Thread.sleep(1000);
                System.out.println(new SimpleDateFormat("HH:mm:ss").format(startTime));
                startTime = new Date(System.currentTimeMillis());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
        //模拟倒计时
    public static void tenDown() throws InterruptedException {
        int num = 10;
        while(true){
            Thread.sleep(1000);
            System.out.println(num--);
            if(num<=0){
                break;
            }
        }
    }
}
7. 线程礼让
让当前正在执行的线程暂停,但不阻塞,将线程由运行状态转为就绪状态,让cpu重新调度,礼让不一定成功,看cpu心情。
//测试线程礼让
public class TestYield implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "线程开始");
        Thread.yield();//线程礼让,礼让不一定成功,看CPU心情
        System.out.println(Thread.currentThread().getName() + "线程停止");
    }
    public static void main(String[] args) {
        TestYield testYield = new TestYield();
        new Thread(testYield,"a").start();
        new Thread(testYield,"b").start();
    }
}
8. 线程强制执行
待该线程执行完后,再执行其他线程,使其他线程阻塞,可以想象为插队。
public class TestJoin implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 500; i++) {
            System.out.println("线程Vip。。。。。" + i);
        }
    }
    public static void main(String[] args) {
        //启动线程
        TestJoin testJoin = new TestJoin();
        Thread thread = new Thread(testJoin);
        thread.start();
        //主线程
        for (int i = 0; i < 300; i++) {
            if(i==200){
                try {
                    thread.join();//线程插队
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("主线程。。。" + i);
        }
    }
}
9. 线程状态

 
10. 线程优先级
线程的优先级用数字表示,范围1-10。优先级低只是表示获得调度的概率低,并不是优先级低不会被调用,具体要看CPU的调度。改变优先级和获取优先级:setPriority(int xxx)、getPriority()。
//测试线程优先级
public class TestPriority {
    public static void main(String[] args) {
        //主线程的优先级
        System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority());
        MyPriority myPriority = new MyPriority();
        Thread t1 = new Thread(myPriority);
        Thread t2 = new Thread(myPriority);
        Thread t3 = new Thread(myPriority);
        Thread t4 = new Thread(myPriority);
        t1.setPriority(8);t1.start();
        t2.setPriority(1);t2.start();
        t3.setPriority(Thread.MAX_PRIORITY);t3.start();
        t4.setPriority(6);t4.start();
    }
}
class MyPriority implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"--->"+Thread.currentThread().getPriority());
    }
}
11. 守护线程
线程分为用户线程和守护线程。虚拟机必须确保用户线程执行完毕,不用等待守护线程执行完毕。
public class TestDaemon {
    public static void main(String[] args) {
        God god = new God();
        Your your = new Your();
        Thread thread = new Thread(god);
        thread.setDaemon(true); //默认是false表示用户线程,正常的线程都是用户线程。
        thread.start();//上帝守护线程启动,虽然god为死循环,但是用户线程结束后,它也结束
        new Thread(your).start();//你,用户线程启动
    }
}
//上帝
class God implements Runnable{
    @Override
    public void run() {
        while(true){
            System.out.println("上帝守护着你");
        }
    }
}
//你
class Your implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 36500; i++) {
            System.out.println("开心每一天");
        }
        System.out.println("=================goodbye==================");
    }
}
12. 线程同步机制
多个线程操作同一个资源。线程同步形成的条件:队列+锁。锁机制:synchronized。
 Synchronized默认锁的是this。锁的对象就是变化的量,需要增删改查的对象。
 同步块:synchronized(obj){ }
//不安全的买票方案
public class UnSafeBuyTicket {
    public static void main(String[] args) {
        BuyTicket station = new BuyTicket();
        new Thread(station,"aa").start();
        new Thread(station,"bb").start();
        new Thread(station,"cc").start();
    }
}
class BuyTicket implements Runnable{
    private int ticketNums = 10;
    boolean flag = true;
    @Override
    public void run() {
        while(flag){
            try {
                buy();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    //同步方法,安全的
    //public synchronized void buy() throws InterruptedException
    public  void buy() throws InterruptedException {
        if(ticketNums<=0){
            flag = false;
            return;
        }
        //模拟延时
        Thread.sleep(100);
        System.out.println(Thread.currentThread().getName() + "拿到----->" + ticketNums--);
    }
}
13. 死锁
死锁产生的条件:
 ① 互斥条件:一个资源每次只能被一个进程使用。
 ② 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
 ③ 不剥夺条件:进程已获得的资源,在未使用完前,不能强行剥夺。
 ④ 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
//测试死锁:多个线程互相抱着对方需要的资源,形成僵持
public class TestDeadLock {
    public static void main(String[] args) {
        Makeup g1 = new Makeup(0, "灰姑娘");
        Makeup g2 = new Makeup(1, "白雪公主");
        g1.start();
        g2.start();
    }
}
//口红
class LipStick{
}
//镜子
class Mirror{
}
class Makeup extends Thread {
    //需要的资源只有一份,用static来保证只有一份
    static LipStick lipStick = new LipStick();
    static Mirror mirror = new Mirror();
    int choice;//选择
    String name;//使用化妆品的人
    public Makeup(int choice, String name) {
        this.choice = choice;
        this.name = name;
    }
    @Override
    public void run() {
        try {
            makeup();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    //化妆,互相持有对方的锁,就是需要拿到对方的资源
    //避免死锁
    private void makeup() throws InterruptedException {
        if (choice == 0) {
            synchronized (lipStick) {
                System.out.println(this.getName() + "获得口红的锁");
                Thread.sleep(2000);
            }
            synchronized (mirror) {
                System.out.println(this.getName() + "获得镜子的锁");
            }
        } else {
            synchronized (mirror) {
                System.out.println(this.getName() + "获得镜子的锁");
                Thread.sleep(2000);
            }
            synchronized (lipStick) {
                System.out.println(this.getName() + "获得口红的锁");
            }
        }
    }
}
14. Lock(锁)

 
public class TestLock {
    public static void main(String[] args) {
        Buyticket buyticket = new Buyticket();
        new Thread(buyticket).start();
        new Thread(buyticket).start();
        new Thread(buyticket).start();
    }
}
class Buyticket implements Runnable{
    int tickeNums = 10;
    //定义lock锁
    private final ReentrantLock lock = new ReentrantLock();
    @Override
    public void run() {
        while(true){
            try {
                lock.lock(); //加锁
                if(tickeNums>0){
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(tickeNums--);
                }else{
                    break;
                }
            }finally {
                lock.unlock();//解锁
            }
        }
    }
}
15. 线程池
//测试线程池
public class TestPool {
    public static void main(String[] args) {
        //1.创建服务,创建线程池
        //newFixedThreadPool  参数为:线程池大小
        ExecutorService service = Executors.newFixedThreadPool(10);
        //执行
        service.execute(new MyThread());
        service.execute(new MyThread());
        service.execute(new MyThread());
        //2.关闭链接
        service.shutdown();
    }
}
class MyThread implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
16. wait和notify
- tt.wait(): 让正在tt对象上活动的线程进入等待状态。
 - wait(): 无限期等待,直至被唤醒。
 - tt.notify():唤醒正在tt对象上等待的线程。
 - tt.notifyAll(): 唤醒tt对象上处于等待的所有线程。
 
17. 生产者消费者
package multiThreads.PCModel;
public class TestBestPC {
    public static void main(String[] args) {
        Resources resources = new Resources();
        Thread threadProduct = new Thread(new Producers(resources));
        Thread threadConsume = new Thread(new Consumers(resources));
        threadProduct.setName("Producers");
        threadConsume.setName("Consumers");
        threadProduct.start();
        threadConsume.start();
    }
}
//资源
class Resources{
    //当前资源的数量
    int num = 0;
    //当前资源的上限
    int size = 100;
}
//消费者
class Consumers implements Runnable{
    private Resources resources;
    public Consumers(Resources resources) {
        this.resources = resources;
    }
    @Override
    public void run() {
        while (true){
            synchronized (resources){
                if(resources.num == 0){
                    System.out.println("========消费者等待=======");
                    try {
                        resources.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                resources.num--;
                System.out.println("消费者:"+Thread.currentThread().getName()+",剩余资源"+resources.num);
                resources.notify();
            }
        }
    }
}
//生产者
class Producers implements Runnable{
    private Resources resources;
    public Producers(Resources resources) {
        this.resources = resources;
    }
    @Override
    public void run() {
        while (true){
            synchronized (resources){
                if(resources.num == resources.size){
                    System.out.println("========生产者等待=======");
                    try {
                        resources.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                resources.num++;
                System.out.println("生产者:"+Thread.currentThread().getName()+",剩余资源"+resources.num);
                resources.notify();
            }
        }
    }
}

