重踏学习Java路上_Day23(多线程)

1:多线程(理解)
    (1)多线程:一个应用程序有多条执行路径
        进程:正在执行的应用程序
        线程:进程的执行单元,执行路径
        单线程:一个应用程序只有一条执行路径
        多线程:一个应用程序有多条执行路径
        
        多进程的意义?
            提高CPU的使用率
        多线程的意义?
            提高应用程序的使用率
    (2)Java程序的运行原理及JVM的启动是多线程的吗?
        A:Java命令去启动JVM,JVM会启动一个进程,该进程会启动一个主线程。
        B:JVM的启动是多线程的,因为它最低有两个线程启动了,主线程和垃圾回收线程。
    (3)多线程的实现方案(自己补齐步骤及代码    掌握)


        A:继承Thread类
        步骤:
            A:自定义类MyThread继承Thread类。
            B:MyThread类里面重写run()?
                为什么是run()方法呢?
                不是类中的所有代码都需要被线程执行的。
                而这个时候,为了区分哪些代码能够被线程执行,java提供了Thread类中的run()用来包含那些被线程执行的代码。
            C:创建对象
            D:启动线程
        
        B:实现Runnable接口(推荐使用,由于Java是单继承多实现,所以用第一种方法会造成该类没有办法继承其他类,或必须要让父类也实现该线程,这样是不行的)
        步骤:
            A:自定义类MyRunnable实现Runnable接口
            B:重写run()方法
            C:创建MyRunnable类的对象
            D:创建Thread类的对象,并把C步骤的对象作为构造参数传递
        
    面试题:
        为什么要重写run()方法                
            该类要重写run()方法,为什么呢?
            不是类中的所有代码都需要被线程执行的。
            而这个时候,为了区分哪些代码能够被线程执行,java提供了Thread类中的run()用来包含那些被线程执行的代码。
        启动线程使用的是那个方法
            start()
        线程能不能多次启动
            不能
            // MyThread my = new MyThread();
            // my.start();
            // // IllegalThreadStateException:非法的线程状态异常
            // // 为什么呢?因为这个相当于是my线程被调用了两次。而不是两个线程启动。
            // my.start();
        run()和start()方法的区别
            run():仅仅是封装被线程执行的代码,直接调用是普通方法
            start():首先启动了线程,然后再由jvm去调用该线程的run()方法。
    
    (4)线程的调度和优先级问题
        A:线程的调度
            a:分时调度
            b:抢占式调度(Java采用的是该调度方式)
        B:获取和设置线程优先级
            a:默认是5
            b:范围是1-10,最高10,最低1
    (5)线程的控制(常见方法)
        A.线程休眠(从运行状态转入阻塞,恢复后回到就绪状态,等待CPU的分配资源)
            public static void sleep(long millis)
        B.线程加入(注意API解释:等待该线程终止。但实际意思是,调用该方法的线程会运行,而放置该代码,调用该语句的线程会阻塞,等到该方法的线程执行完毕,主线程(即放置代码的线程)才会回到就绪状态)
            public final void join()
        C.线程礼让(暂停当前正在执行的线程对象,并执行其他线程。其实是暂停了一下,就回到就绪状态,让其他线程有机会使用CPU,减少因单一线程抢占使用过多,其他线程无法执行,达到相对平衡,但只能是相对,不可能达到绝对平衡)
            public static void yield()
        D.后台线程
            public final void setDaemon(boolean on)(调用该方法的线程会变成后台线程,或叫守护线程。当所有非守护线程执行完后,守护进程也会接着消失,不管守护线程时候执行完他所需要执行的代码)
        E.中断线程
            public final void stop() (太暴力,不建议使用,由于执行了这个方法的线程马上终止所有操作,它后面的所有代码都不会执行,所以很容易会出现其他线程由于你的终止而产生崩毁)
            public void interrupt() (推荐使用,调用此方法的线程会抛出一个异常,然后在catch处捕获处理,最后执行后面的代码,以后关闭线程,这样比较好,因为是比较完善的执行退出机制)

  F.Thread类的基本获取和设置方法
    public final String getName()
    public final void setName(String name)
    其实通过构造方法也可以给线程起名字
  思考:
    如何获取main方法所在的线程名称呢?
    public static Thread currentThread()
    这样就可以获取任意方法所在的线程名称
    Thread.currentThread.setName("啦啦");

  G.如何设置和获取线程优先级
    public final int getPriority()
    public final void setPriority(int newPriority)


    (6)线程的生命周期(参照    线程生命周期图解.bmp)


        A:新建 -- 线程创建
        B:就绪 -- 有使用权,没有执行权
        C:运行 -- 有使用权,有执行权
        D:阻塞 -- 没有执行权,没有使用权
        E:死亡 -- 退出线程
    (7)电影院卖票程序的实现
        A:继承Thread类
        B:实现Runnable接口
    (8)电影院卖票程序出问题
        A:为了更符合真实的场景,加入了休眠100毫秒。
        B:卖票问题
            a:同票多次
            b:负数票
    (9)多线程安全问题的原因(也是我们以后判断一个程序是否有线程安全问题的依据)
        A:是否有多线程环境
        B:是否有共享数据
        C:是否有多条语句操作共享数据
    (10)同步解决线程安全问题
        A:同步代码块
            synchronized(对象){
                需要被同步的代码;
            }
            
            这里的锁对象可以是任意对象。
            
        B:同步方法
        这里的锁对象是this
         private synchronized void sellTicket() {
            if (tickets > 0) {
            try {
                    Thread.sleep(100);
            } catch (InterruptedException e) {
                    e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()
                        + "正在出售第" + (tickets--) + "张票 ");
            }
        }    
            
        
        C:静态同步方法
        这里的锁对象是当前类的字节码文件对象(反射再讲字节码文件对象)
        private static synchronized void sellTicket() {
            if (tickets > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()
                + "正在出售第" + (tickets--) + "张票 ");
            }
        }
        
    
    (11)回顾以前的线程安全的类
        A:StringBuffer
        B:Vector
        C:Hashtable
        D:如何把一个线程不安全的集合类变成一个线程安全的集合类
            用Collections工具类的方法即可。
    思考题:
        jvm虚拟机的启动是单线程的还是多线程的?
            多线程的。
        原因是垃圾回收线程也要先启动,否则很容易会出现内存溢出。
        现在的垃圾回收线程加上前面的主线程,最低启动了两个线程,所以,jvm的启动其实是多线程的。

        进程:
            正在运行的程序,是系统进行资源分配和调用的独立单位。
            每一个进程都有它自己的内存空间和系统资源。
        线程:
            是进程中的单个顺序控制流,是一条执行路径
            一个进程如果只有一条执行路径,则称为单线程程序。
            一个进程如果有多条执行路径,则称为多线程程序。
    大家注意两个词汇的区别:并行和并发。
        前者是逻辑上同时发生,指在某一个时间内同时运行多个程序。

    Java程序的运行原理:
        由java命令启动JVM,JVM启动就相当于启动了一个进程。
        接着有该进程创建了一个主线程去调用main方法。
 --------------------------------------------------------------------------------------------------------------------------------------      

1:要想了解多线程,必须先了解线程,而要想了解线程,必须先了解进程,因为线程是依赖于进程而存在。

2:什么是进程?
    通过任务管理器我们就看到了进程的存在。
    而通过观察,我们发现只有运行的程序才会出现进程。
    进程:就是正在运行的程序。
    进程是系统进行资源分配和调用的独立单位。每一个进程都有它自己的内存空间和系统资源。
    
3:多进程有什么意义呢?
    单进程的计算机只能做一件事情,而我们现在的计算机都可以做多件事情。
    举例:一边玩游戏(游戏进程),一边听音乐(音乐进程)。
    也就是说现在的计算机都是支持多进程的,可以在一个时间段内执行多个任务。
    并且呢,可以提高CPU的使用率。
    
    问题:
        一边玩游戏,一边听音乐是同时进行的吗?
        不是。因为单CPU在某一个时间点上只能做一件事情。
        而我们在玩游戏,或者听音乐的时候,是CPU在做着程序间的高效切换让我们觉得是同时进行的。
        
4:什么是线程呢?
    在同一个进程内又可以执行多个任务,而这每一个任务我就可以看出是一个线程。
    线程:是程序的执行单元,执行路径。是程序使用CPU的最基本单位。
    单线程:如果程序只有一条执行路径。
    多线程:如果程序有多条执行路径。
    
5:多线程有什么意义呢?
    多线程的存在,不是提高程序的执行速度。其实是为了提高应用程序的使用率。
    程序的执行其实都是在抢CPU的资源,CPU的执行权。
    多个进程是在抢这个资源,而其中的某一个进程如果执行路径比较多,就会有更高的几率抢到CPU的执行权。
    我们是不敢保证哪一个线程能够在哪个时刻抢到,所以线程的执行有随机性。

posted @ 2015-07-09 16:10  暴走骑士  阅读(190)  评论(0编辑  收藏  举报