java基础之多线程

多线程:
    概述: 进程有多条执行路径, 合成为: 多线程.
        进程: 可执行程序(文件), 例如: .exe
            //可以把进程理解为一辆车.
        线程: 进程的执行路径(执行单元)
            //可以把线程理解为: 是马路

        记忆:
            1. 一台电脑上可以有多个进程, 这些进程之间的数据是相互隔离的.
                //例如: qq.exe,  飞秋.exe
            2. 一个进程可以有多条线程, 这些线程可以共享该进程的数据.
                //例如: 往QQ群共享放一个文件, 该群中的所有的用户都可以下载.

    多线程并行和并发的区别是什么:
        并行: 两个(多个)线程同时执行.   //前提: 需要多核CPU

        并发: 
            两个(多个)线程同时请求执行, 但是CPU同一瞬间只能执行一个线程,
            于是就安排这些线程交替执行, 因为时间间隔非常短, 我们看起来好像是同时执行的, 其实不是.

    多线程的实现方式:
        方式一: 继承Thread类.
            步骤:
                1) 定义一个类(MyThread), 继承Thread类.
                2) 重写Thread#run().
                   //重写Thread类中的run()方法.
                3) 把要执行的代码放入run()方法中.
                4) 在测试类中,创建线程对象.
                5) 开启线程.        //start()

                注意事项:
                    A: 如果调用run()方法, 只是普通的方法调用.
                    B: 开启线程必须调用start()方法, 该方法会自动去调用run()方法.            
                    C: 同一线程不能重复开启, 否则会报: IllegalThreadStateException异常.

        方式二: 实现Runnable接口.
            步骤:
                1) 定义一个类(MyRunnable), 实现Runnable接口.
                2) 重写Runnable#run().
                3) 把要执行的代码放入run()方法中.
                4) 在测试类中, 创建Runnable接口的子类对象, 
                    MyRunnable mr = new MyRunnable();
                   并将其作为参数传入Thread类的构造, 创建线程对象.
                    Thread th = new Thread(mr);
                5) 开启线程.        //start()

        方式三: 结合线程池使用(实现Callable接口).         //暂时了解即可.

    多线程的执行特点是什么:
        随机性, 延迟性.
        因为CPU在做着高效的切换.

    多线程案例: 模拟卖票.
        //需求: 四个窗口, 卖100张票.
        出现的问题:
            出现负数:if条件
            出现重复值:ticket--

        解决方案:
            采用 同步代码块解决.

    Thread类中的成员:
        构造方法:
            public Thread();
            public Thread(String name);
            public Thread(Runnable target);
            public Thread(Runnable target,String name);

        成员方法:
            run();  //里边定义的是线程要执行的代码, 该方法会自动被start()方法调用.
            start();  //开启线程, 会自动调用run().
            getName();
            setName();
            sleep();  //休眠线程, 单位是: 毫秒.
            currentThread();  //获取当前正在执行的线程对象(的引用).

    同步:
        概述/作用:
            多线程(环境) 并发 操作同一数据, 有可能引发安全问题, 就需要用到同步解决.
        分类:
            同步代码块:
                格式:
                    synchronized(锁对象) {
                        //要加锁的代码
                    }
                锁对象:
                    1) 同步代码块的锁对象可以是任意类型的对象.
                    2) 必须使用同一把锁, 否则可能出现锁不住的情况.

            同步方法:
                静态方法:
                    锁对象: 该类的字节码文件对象.
                非静态方法:
                    锁对象: this


    多线程的难点(一般只在面试的时候用, 工作中基本不用)
        死锁:
            死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的
            一种阻塞的现象,若无外力作用,它们都将无法推进下去。

        多线程的生命周期:
            新建, 就绪, 运行(有可能发生阻塞和等待), 死亡.

    扩展的知识:
        1) 匿名内部类:       //本质是一个对象.          //记忆&掌握
            内部类:
                概述: 类里边还有一个类, 里边那个类叫内部类, 外边那个类叫外部类.
                分类:
                    成员内部类:  定义在成员位置的内部类.
                    局部内部类:  定义在局部位置的内部类.

            概述:
                就是没有名字的 局部内部类.

            格式:
                new 类名或者接口名(){
                    //重写类或者接口中 所有的 抽象方法;
                };

            本质:
                专业版: 就是一个继承了类或者实现了接口的 匿名的子类对象.
                大白话: 匿名内部类不是类, 而是子类对象.

            匿名内部类在实际开发中的应用:
                1) 当对 对象方法(成员方法) 仅调用一次的时候.
                2) 可以作为方法的实参进行传递.

            个人建议:
                当接口中或者抽象类中的 抽象方法仅有一个的时候, 就可以 考虑使用匿名内部类.

        2) 实现Runnable接口的原理.     //多态.
            背景:
                多线程的第一种实现方式是: 继承Thread类, 因为我们自定义的类(MyThread)是Thread类的子类,
                所以MyThread类的对象调用start()方法的时候, 自动调用MyThread#run(), 这个我们可以理解, 

                但是MyRunnable类是实现了Runnable接口, 而Runnable接口的run()方法和Thread#start()没有关系, 
                问: 为什么Thread#start(), 会自动调用Runnable接口的子类(MyRunnable)中的 run()方法呢?

            简化版的源码:
                测试类中的代码
                public static void main(String[] args) {
                    MyRunnable mr = new MyRunnable();
                    Thread th = new Thread(mr);
                    th.start(); //问: 为什么会自动调用 MyRunnable#run();
                }

                public class Thread {
                    private Runnable target;            //new MyRunnable();
                    public Thread(Runnable target) {    //new MyRunnable();
                        this.target = target;
                    }

                    public void run() {
                        if(target != null) {
                            target.run();               //new MyRunnable().run();
                        }
                    }

                }

         从Eclipse贴过来的源码:

            public class Thread {
                 private Runnable target;
                 public Thread(Runnable target) {
                    init(null, target, "Thread-" + nextThreadNum(), 0);
                }

                private void init(ThreadGroup g, Runnable target, String name,
                  long stackSize) {
                    init(g, target, name, stackSize, null);
                }

                private void init(ThreadGroup g, Runnable target, String name,
                  long stackSize, AccessControlContext acc) {
                    this.target = target;
                }

                 @Override
                public void run() {
                    if (target != null) {
                        target.run();
                    }
                }
            }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章