JavaSE-09 Thread 多线程
1. 线程简介
1.1 普通方法调用和多线程

1.2 程序、进程、线程
- 程序跑起来编程进程,进程里面分为若干个线程 :例如main函数就是主线程(是系统入口,用于执行多个程序),gc垃圾回收机制也是一个线程
 - 多线程是模拟出来的,真正的多线程是指很多cpu,即多核,但是因为cpu执行代码切换的很快,所以有同时执行的感觉
 - 多个线程是由调度器安排调度与操作系统相关的,控制到cpu先后顺序
 - 对同一个资源操作时,会发生资源抢夺的问题,需要加入并发控制
 
2. 线程创建:com.fenfen.Thread.Demo1
2.1继承Thread类
| 三步走: | 
|---|
| 1.自定义线程类继承Thread类 | 
| 2.重写run()方法,编写线程执行力 | 
| 3.创建线程对象,调用start()方法启动线程 | 
        public class TestTread1 extends Thread{
            @Override
            public void run() {
                //run 方法线程体
                for (int i = 0; i < 20; i++) {
                    System.out.println("我在通宵肝代码---"+i);
                }
            }
            public static void main(String[] args) {
                //main方法,主线程
                //创建一个线程对象,并调用start方法
                TestTread1 testTread1 = new TestTread1();
                testTread1.start();
                //如果是run方法就是正常的先跑run方法上面的
                testTread1.run();
                for (int i = 0; i < 200; i++) {
                    System.out.println("我在学习多线程---"+i);
                }
                /*
                输出结果是交替执行的,由cpu调度执行
                 */
            }
2.2 用继承thread实现网图下载的多线程
学完io流后记得补代码
2.3 实现runnable接口
| 三步走: | 
|---|
| 1.定义MyRunnable类实现Runnable接口 | 
| 2.实现run()方法,编写线程执行体 | 
| 3.创建线程对象,传入目标对象+调用start()方法启动线程 | 
        public class TestThread3 implements Runnable{
            @Override
            public void run() {
                //run 方法线程体
                for (int i = 0; i < 20; i++) {
                    System.out.println("我在通宵肝代码---"+i);
                }
            }
            public static void main(String[] args) {
                //main方法,主线程
                //创建Runnable接口实现类对象,并调用start方法
                TestThread3 testTread3 = new TestThread3();
                //创建线程对象,通过线程对象来开启我们的线程,代理
                Thread thread = new Thread(testTread3);
                thread.start();
                //new Thread(testTread3).start();或者直接一句这个
                for (int i = 0; i < 200; i++) {
                    System.out.println("我在学习多线程---"+i);
                }
                /*
                1、去看源码发现,本质是因为:Thread也实现了Runnable接口,Runnable就一个run方法在里面
                2、继承是单继承,推荐使用Runnable方法
                 */
            }
        }
2.4 初始并发问题
多个线程操作同一个资源的情况下,并发出现问题,线程不安全了,数据紊乱
        public class TestThread4 implements Runnable{
            //票数
            private int ticketnums = 10;
            @Override
            public void run() {
                while (true){
                    if (ticketnums<=0){
                        break;
                    }
                    //模拟延迟sleep
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticketnums--+"票");
                }
            }
            public static void main(String[] args) {
                TestThread4 ticket = new TestThread4();
                new Thread(ticket,"小明").start();
                new Thread(ticket,"小芬").start();
                new Thread(ticket,"黄牛党").start();
            }
        }
2.5 利用多线程实现龟兔赛跑
| 思路: | 
|---|
| 1.fori循环 | 
| 2.方法用boolean写一个判断是否完成比赛,传递i过去 | 
| 3.比赛结束跳出循环 | 
| 4.新建两个线程调用 | 
| 5.让兔子线程休息,记得try和catch一下 | 
        public class Race implements Runnable{
            //胜利者
            private static String winner;
            @Override
            public void run() {
                for (int i = 0; i <= 100; i++) {
                    //模拟兔子休息sleep
                    if(Thread.currentThread().getName().equals("兔子")&&i%10==0){
                        try {
                            Thread.sleep(1);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    //判断比赛是否结束
                    boolean flag = gameover(i);
                    //如果比赛结束了,就停止
                    if(flag){
                        break;
                    }
                    System.out.println(Thread.currentThread().getName()+"跑了"+i+"步");
                }
            }
            //判断完成比赛
            private boolean gameover(int steps){
                //判断是否有胜利者
                if (winner!=null){
                    return true;
                }{
                    if (steps >=100){
                        winner = Thread.currentThread().getName();
                        System.out.println("winner is "+ winner);
                        return true;
                    }
                }
                    return false;
            }
            public static void main(String[] args) {
                Race race = new Race();
                new Thread(race,"兔子").start();
                new Thread(race,"乌龟").start();
            }
        }
2.6实现Callable接口
| 好几步走: | 
|---|
| 1.实现Callable接口,需要返回值类型 | 
| 2.重写call方法,需要抛出异常 | 
| 3.创建目标对象 | 
| 4.创建执行服务 | 
| 5.提交执行 | 
| 6.获取结果 | 
| 7.关闭服务 | 
了解就好,如果以后用到再学,再来补,先鸽一下(狗头)
2.7 静态代理模式
| 思路: | 
|---|
| 1.两个类都改写接口的方法 | 
| 2.将真实对象通过参数传进去(构造器),代理对象从而代理真实角色 | 
| 好处: | 
| 代理对象可以做很多真实对象做不了的事情,真实对象专注做自己的事情 | 
| 就是线程的底部原理 | 
            public class StaticProxy {       
            public static void main(String[] args) {
                You you = new You();
                //这边用lamda表达式表示:Thread代理一个真实的Runnable接口,并且调用了start方法
                new Thread(()-> System.out.println("我爱你")).start();
                //或者精简成new WeddingCompany(new You()).HappyMarry();
                WeddingCompany weddingCompany = new WeddingCompany(new You());
                weddingCompany.HappyMarry();
            }
        }
        interface Marry{
            void HappyMarry();
        }
        //真实角色
        class You implements Marry{
            @Override
            public void HappyMarry() {
                System.out.println("要结婚啦");
            }
        }
        //代理角色,帮助
        class WeddingCompany implements Marry{
            private Marry target;
            public WeddingCompany(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("结婚之前,布置现场");
            }
        }
2.8 Lamdba表达式
2.8.1 基本内容
- Lamdba表达式属于函数式编程
 - 例如:a->System.out.println("我在学习多线程->"+i);
 - 
函数式接口的定义:任何接口只包含了一个抽象方法,那就是函数式接口,就可以通过lambda表达式来创建该接口的对象
2.8.2 简略代码的方法
 - 静态内部类
 
        public class TestLambda2 {
            //利用静态内部类的方式:加上static
            static class Like11 implements ILike1{
                @Override
                public void lambda() {
                    System.out.println("i like lambda1");
                }
            }
            public static void main(String[] args) {
                Like11 like11 = new Like11();
                like11.lambda();
            }
        }
                //1、定义一个函数式接口
                interface ILike1 {
                    void lambda();
                }
- 局部内部类
 
        public class TestLambda3 {
            public static void main(String[] args) {
                class Like3 implements ILike3{
                    @Override
                    public void lambda() {
                        System.out.println("i like lambda3");
                    }
                }
                Like3 like3 = new Like3();
                like3.lambda();
            }
        }
        //1、定义一个函数式接口
        interface ILike3 {
            void lambda();
        }
- 匿名内部类:没有类的名称
 
        public class TestLamdba4 {
            public static void main(String[] args) {
                ILike4 like4 = new ILike4(){
                @Override
                public void lambda() {
                    System.out.println("i like lambda4");
                }
            };
                like4.lambda();
            }
        }
        //1、定义一个函数式接口
        interface ILike4 {
            void lambda();
        }
- 用lambda简化
 
        public class TestLambda5 {
            public static void main(String[] args) {
                ILike5 like5= ()->{
                    System.out.println("i like lambda5");
                };
                like5.lambda();
            }
        }
        //1、定义一个函数式接口
        interface ILike5 {
            void lambda();
        }
再写一个
- 正常接口代码2
 
        public class TestLamdba6 {
            public static void main(String[] args) {
                Love love = new Love();
                love.love(666);
            }
        }
        interface Ilove{
            void love(int a );
        }
        class Love implements Ilove{
            @Override
            public void love(int a) {
                System.out.println("i love life-->"+a);
            }
        }
- 匿名内部类2
 
        public class TestLamdba7 {
            public static void main(String[] args) {
                Ilove1 ilove1 = new Ilove1(){//记得改成接口的类
                    @Override
                    public void love(int a) {
                        System.out.println("i love life-->"+a);
                    }
                };
                ilove1.love(888);
            }
        }
        interface Ilove1{
            void love(int a );
        }
7.用lambda简化2
        public static void main(String[] args) {
            Ilove2 ilove2 = (int a)-> {
                    System.out.println("i love life-->"+a);
                };
            //再简化:①去掉参数类型
            ilove2 = (a)-> {
                System.out.println("i love life-->"+a);
            };
            //再简化:把括号都简化没了
            ilove2 = a->{
                System.out.println("i love life-->"+a);
            };
            ilove2.love(888);
        }
    }
    interface Ilove2{
        void love(int a );
    }
- 用lambda简化多个参数
 
        public class TestLamdba9 {
            public static void main(String[] args) {
                Ilove3 ilove3 = null;
                ilove3 = (a,b)-> {
                    System.out.println("i love you-->"+a+" "+b);
                };
                ilove3.love(520,1314);
                /*
                多个参数也可以去掉参数类型,要去掉就全部去掉,并且带上括号
                 */
            }
        }
        interface Ilove3{
            void love(int a,int b );
        }









