一文搞懂进程&线程

发布时间:2024年01月17日

? ? ? ? 小玉这几天在复习多线程篇知识,最近有点偷懒了,博客要常常写!加油!? 那么接下来就跟着小玉来入门多线程吧.....


目录

1.什么是进程?

2.什么是线程?

2.1进程&线程的区别是什么?

3.创建多线程的几种方法

3.1方法一:继承Thread类

3.2方法二:实现Runnable接口?

3.3方法三:采用匿名内部类?

3.3.1继承Thread,采用匿名内部类?

3.3.2实现Runnable,采用匿名内部类

3.4方法四:采用Lambda表达式 (最推荐使用)

4.Thread常见构造方法及属性?

? ? ? ? ?



1.什么是进程?

? ? ? ? 在操作系统没有引入进程之前,由于CPU一个核心一次只能执行一个程序,所以多个程序只能顺序执行,像以前的手机QQ退出后就无法接受消息了.....CPU的速度很快,磁盘、网路等IO的速度很慢,造成CPU会有大量空闲的时间,此时CPU的利用率很低,为了解决CPU的利用率低的问题,操作系统引入了进程以及中断处理,实现了在同一时间段内,多个程序的"并发"执行,这个程序执行一点,那个程序执行一点,这样并发交替的执行大大提高了CPU的利用率。
????????简单来说:跑起来的程序就是进程!一个.exe文件就是一个进程,例如QQ,微信,CCTALK......

2.什么是线程?

????????一个线程就是一个 "执行流". 每个线程之间都可以按照顺序执行自己的代码. 多个线程之间 "同时" 执行着多份代码.就例如QQ:QQ是进程,但是QQ可以同时兼顾聊天视频,看朋友圈,发图片等等功能,这些功能可以同时执行,这即是线程.?

? ? ? ? 线程很好的解决了"CPU资源浪费的情况",可以在CPU快速调度的时候,充分减少等待时间,提高计算机的使用效率.现如今,"并发编程"已经成为主流,学习多线程也是刚需!

2.1进程&线程的区别是什么?

? ? ? ? 很多朋友在了解完进程和线程这两概念之后就陷入迷茫,我们下面就来探索一下他们之间的区别究竟在哪........

  • 进程包含线程

? ? ? ? 好,第一点盖棺定论!一个包含关系直击痛处!? 一个进程至少包含一个线程,也可以包含多个线程,线程不可脱离进程存在.那么既然包含关系存在那么我们能得出有效结论:

创建线程比创建进程更快.
销毁线程比销毁进程更快.
调度线程比调度进程更快.
(即:线程比进程更轻量~~~)

  • 线程是独立的执行流,同一个进程的多个线程之间共享同一份资源

? ? ? ? OK! 我们如果将进程比喻成一个"工厂",那么线程就是工厂的"流水线",他们之间可以并发执行.那么"共享资源"到底在说什么? 资源----即内存空间文件描述附表.?

? ? ? ? 只有这个进程的第一个线程创建的时候才会去申请资源,这些资源申请完之后,后续在该进程里创建新的线程之后就无须再申请了.

  • 线程是操作系统资源调度的最小单位,进程是操作系统资源分配的最小单位.?

? ? ? ? 有了前面的结论铺垫我们也能得出这个结论,我们之前说的进程也可以进行调度,这里指的是这个进程只有一个线程的时候,操作系统调度的其实是这个进程的线程,所以我们才会以为进程在频调度......?

  • 进程具有独立性和隔离性.一个进程挂了不影响其他进程,但是一个线程挂了可能会吧进程和进程里的其他线程都带走

? ? ? ? 就比如QQ哪天挂了,但是微信不受影响,但是要是QQ发不了消息了,可能就进入死机状态,看朋友圈打视频可能都干不了了..........

????????好,以上就是进程&线程的区别,大家可以仔细体会一下,这里很好理解,希望去哪个大家不要想的太多,复杂化了........


3.创建多线程的几种方法

? ? ? ? 那么我们了解完了进程&线程,在Java中我们重点学习多线程,那么如何创建一个多线程呢?我们打开IDEA:像往常一样,建一个普通的文件:

3.1方法一:继承Thread类

? ? ? ? 在类外创建一个类并且继承Thread类,重写run();这里实际上是针对原本的Thread库实现扩展,在里面我们打印上一句"hello t ";在下面public类里我们创建子类实例t,并且调用t.start()?创建并启动新线程!

????????上述代码中我们涉及到的进程是Java进程,其中包含两个线程:主线程main 和我们创建的线程t.接下来我们再感受一个什么叫:每个线程都是独立的执行流.

?????????我们设置两个死循环,如果是以前的思维:那么程序进入main之后,遇到t.start(),会在这个循环里出不来,那样就不可能执行到下面的第二个死循环了,但是我们观察控制台:

? ? ? ? 我们可以发现:这里能交替打印出 hello t 和 hello main 如果想更清楚一点,我们可以设置休眠:?

此时在观察控制台:?

????????我们就能更清楚的看到交替的过程了,关于为什么有时候先打印hello t有时候先打印hello main,这里小玉想说:系统的调度是无序/随机的,虽然我们各自设置了休眠,但是我们无法控制哪个线程先执行. 这里就能体现那句话了,什么来着?每个线程都是独立的执行流.

3.2方法二:实现Runnable接口?

? ? ? ? 那么介绍完了第一个方法,还有的就是:实现Runnable接口,看代码:

class MyThread2 implements Runnable{
    @Override
    public void run() {
        while (true) {
            System.out.println("hello t");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class ThreadDemo2 {
    public static void main(String[] args) {
        MyThread2 myThread2 = new MyThread2();
        Thread t = new Thread(myThread2);
        t.start();
        
        while (true){
            System.out.println("hello main ");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

? ? ? ? 结果跟方法一是一样的,这里就不放了,朋友们自行实践一下吧~~~?


这里需要注意! 重写的是run()方法,但是我们启动新线程却是调用start()方法,可否启动新线程直接调用run()呢??

run() 与start() 的区别:?

  • run()方法可以视作新线程的入口方法,就类似于主线程的main()方法一样,在我们调用start()方法是会自动调用run()方法,因为这是我们重写的方法.
  • run()方法不会创建新线程,只是线程的入口指示牌,但是start()方法会创建一个新线程!?

我们来看例子吧:

class MyThread2 implements Runnable{
    @Override
    public void run() {
        while (true) {
            System.out.println("hello t");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class ThreadDemo2 {
    public static void main(String[] args) {
        MyThread2 myThread2 = new MyThread2();
        Thread t = new Thread(myThread2);

//        t.start();
        t.run();

        while (true){
            System.out.println("hello main ");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

只需要改动一行代码,我们观察控制台:

我们发现,hello main不打印了,为什么?看图解:

此时我们的线程只有主线程main,main进入第一个死循环之后就出不去了,只能一秒一个hello t......?


你们理解什么是:线程是独立的执行流这句话了吗??

3.3方法三:采用匿名内部类?

????????所谓的匿名内部类就是定义在类里面的类,过两天小玉深度学习一下,写一篇博客吧....小玉也不是很懂......?

3.3.1继承Thread,采用匿名内部类?
public class ThreadDemo3 {
    public static void main(String[] args) {
        Thread t = new Thread(){
            @Override
            public void run() {
                while (true){
                    System.out.println("hello t");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        
        t.start();

        while (true){
            System.out.println("hello main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

运行结果同方法一?

3.3.2实现Runnable,采用匿名内部类
public class ThreadDemo4{
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable(){
            @Override
            public void run() {
                while (true){
                    System.out.println("hello t");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });

        t.start();
        
        while (true){
            System.out.println("hello main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


}

注意了这里不需要implements Runnable直接在括号里new Runnable即可;效果相同~~~?

大括号{放在哪里就是针对哪个类的内部类,大家区分清楚.

3.4方法四:采用Lambda表达式 (最推荐使用)

Lambda?表达式实际上就是一个匿名函数,本质上就是一个连名字都不配拥有的函数,用完就丢,一次性.

public class ThreadDemo5 {
    public static void main(String[] args) {
        Thread t = new Thread(()->{
            while (true){
                System.out.println("hello t");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        t.start();

        while (true){
            System.out.println("hello main ");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

我们发现这种方法连run()都不需要写了......很方便,但是大家注意格式:?


4.Thread常见构造方法及属性?

构造方法:

属性:

关于是否是后台线程,这里贤臣共分为前台和后台线程,前台线程会阻止线程结束,当前台线程结束的时候,整个线程才能结束,这个isDaemon()方法默认是false,也就是默认是前台线程,了解即可.......


? ? ? ? 小玉就说这么多吧......更多精彩内容小玉会努力更新的,欢迎留言讨论!再见了~~~~?

????????

? ? ? ? ?

文章来源:https://blog.csdn.net/m0_73609313/article/details/135573445
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。