多线程

多线程

程序:为完成特定任务,用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象。

进程:是程序的一次执行过程,或者是正在运行的程序。是一个动态的过程,有它自身的产生、存在、和消亡的过程。——生命周期。

  • 如,运行中的QQ,运行中的MP3播放器
  • 程序是静态的,进程是动态的
  • 进程作为资源分配的单位,系统在运行时会为每个内存分配不同的内存区域

线程:进程可进一步细化为线程,是程序内部的一条执行路径。

  • 若一个进程同一时间并行执行多个线程,就是支持多线程的
  • 线程作为调度和执行的单位,每个线程都拥有独立的运行栈和程序计数器(PC),线程切换的开销小
  • 一个进程中的多个线程共享相同的内存单元/内存地址空间->它们从同一堆中分配对象,可以访问相同的变量和对象。这就使得线程间通信更简便,高效。但多个线程操作共享的系统资源可能会带来安全的隐患

单核CPU和多核CPU的理解:

  • 单核CPU,其实是一种假的多线程。单核CPU上运行的多线程程序,同一时间只能一个线程在跑,系统给每个线程分配时间片来执行,每个时间片大概10ms左右,看起来像是同时在跑多个线程,但实际是每个线程跑一点点就换到其他线程继续跑。举个例子,一个厨房里只有一个厨师在干活,这个时候来了三个客人,分别下了一个汤,一个小炒,一个煮螺蛳粉(电磁炉煮)。但是由于只有一个厨师,他在一个时间内只能做一件事(同一时间只能一个线程在跑),要么煮螺蛳粉,要么炒菜,要么煲汤,不可能说一个人同时做三件事。但是这个厨师能力很强(单核CPU主频很高),他先花1分钟把螺蛳粉都泡好,然后停下来再花1分钟把煲汤需要弄的弄好,然后再花1分钟把炒菜需要的都放到锅里,然后又回去弄螺蛳粉,因为这个厨师能力非常强,他能合理的分配时间来做这三件事,而且做的特别快,一下子就把这三道菜做好了,让你感觉厨房里好像有三个厨师分别在做这三道菜一样,但实际是他一个人挣了三个人的工资。
  • 多核CPU,是真正意义上的多线程,同一时间多个CPU同时跑其他的程序,效率很高。
  • 一个Java应用程序java.exe,其实至少有三个线程:main()主线程,gc()垃圾回收线程,异常处理线程。当然,如果发生异常,会影响主线程。

并行和并发:

  • 并发:一个应用程序(进程)如果可以开启多个线程,让多个线程同时存在,但是交替执行(参考上面的单核CPU概念),则称之为并发执行
  • 并行:一个应用程序能并行执行,那么就一定是运行在多核处理器上。此时,程序中的每个线程都将分配到一个独立的处理器上核上,因此可以并行执行

多线程程序的优点:

  1. 提高应用程序的响应。对图形化界面更有意义,增强用户的体验
  2. 提高计算机系统CPU的利用率
  3. 改善程序结构。将既长又复杂的进程分为多个线程,独立运行,利于理解和修改。

多线程的创建:

  • 方式一:通过继承于Thread类

    // 1.创建一个继承于Thread类的子类
    class MyThread extends Thread {
        // 2.重写Thread类的run()方法-->将此线程的的操作声明在run()方法中
        // 遍历100以内的偶数
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                if (i % 2 == 0) {
                    System.out.println(i);
                }
            }
        }
    
    }
    
    public class ThreadTest {
        public static void main(String[] args) {
            // 3.在测试类中创建Thread类的子类的对象
            MyThread mt = new MyThread();
    
            // 4.通过此对象调用Thread类中的start()方法
            mt.start();
            
            // 问题一:不能通过直接调用run()的方式启动线程
            // mt.run(); 这是错的
            
            // 问题二:不可以还让已经start()的线程去执行,否则会报IllegalTheradStateException线程非法的异常。
            // 多次启动一个线程是非法的。特别是当线程已经结束执行后,不能再重新启动。
            // mt.start();
            
            // 需要重新创建一个线程的对象才可以start()
            MyThread mt2 = new MyThread();
            mt2.start();
            
            // 还可以通过创建匿名子类的方式
            new Thread(){
                @Override
                public void run() {
                    for (int i = 0; i < 100; i++) {
                        if (i % 2 == 0) {
                            System.out.println(i);
                        }
                    }
                }
            }.start();
        }
    }
    
  • Thread中常用的方法:

    1. start():启动当前线程,调用当前线程的run()
    2. run():通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
    3. currentThread:静态方法,返回对当前正在执行的线程对象的引用
    4. getName():获取当前线程的名字
    5. setName():设置当前线程的名字
    6. yield():暂停当前正在执行的线程对象,并执行其他线程
    7. join():在线程a中调用线程b的join()方法,此时线程a就会进入阻塞状态,直到线程b完全执行完以后,线程a才会结束阻塞状态
    8. sleep(long millis):在指定的毫秒数内让当前正在执行的线程休眠(暂停执行)
    9. isAlive():判断当前线程是否还存活
  • 线程的调度

    • 调度策略
      • 以 “时间片” 的形式进行调度
      • 抢占式:高优先级的线程抢占CPU
    • Java的调度方法
      • 同优先级的线程组成先进先出队列(先到先得服务),使用时间片的策略
      • 对高优先级使用抢占式策略
    • 线程的优先级等级
      • MAX_PRIORITY:10
      • MIN_PRIORITY:1
      • NORM_PRIORITY:5 --> 默认优先级
    • 涉及的方法
      • getPriority():返回线程的优先级等级
      • setPriority(int p):设置线程的优先级的等级
    • 说明:
      • 线程创建时继承父线程的优先级等级
      • 低优先级只是获得CPU调度的概率低,并非是在高优先级线程之后才被调用
  • 方式二:实现Runnable接口

    // 1.创建一个实现了Runnable接口的类
    class MyThread1 implements Runnable {
    
        // 2.实现类去实现Runnable接口的抽象方法:run()
        @Override
        public void run() {
            for (int i = 0; i < 100; i++) {
                if (i % 2 == 0) {
                    System.out.println(i);
                }
            }
        }
    }
    
    public class ThreadTest1 {
        public static void main(String[] args) {
            // 3.创建实现类的对象
            MyThread1 myThread1 = new MyThread1();
    
            // 4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
            Thread t1 = new Thread(myThread1);
    
            // 5.通过Thread类的对象调用start():① 启动线程   ②调用当前线程的run()方法
            t1.start();
        }
    }
    
  • 比较创建多线程的两种方式:

    • 开发中,优先选择实现Runnable接口的方式(面向接口编程)
    • 原因:
      1. 实现接口的方式没有类的单继承的局限性
      2. 实现接口的方式更适合用来处理多线程共享数据的情况

线程的生命周期:

要想实现多线程,必须在主线程中创建新的线程对象。Java语言使用Thread类及其子类的对象来表示线程,在它的一个完整的生命周期中通常要经历如下的五种状态:

  • 新建:当一个Thread类及其子类的对象被声明创建时,新生的线程对象处于新建状态
  • 就绪:处于新建状态的线程被start()之后,将进入线程队列等待CPU时间片,此时它已具备了运行的条件,只是没分配到CPU资源
  • 运行:当就绪的线程被调度并获得CPU的资源时,便进入运行状态,run()方法中国定义了线程的操作和功能
  • 阻塞:在某种特殊情况下,被人为挂起或执行输入输出操作时,让出CPU并临时终止自己的执行,进入阻塞状态
  • 死亡:线程完成了它的全部工作或者线程被提前强制性地中止或线程出现异常且没处理导致结束
生命周期图
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352

推荐阅读更多精彩内容