【JavaEE】多线程(1)


🎆🎆🎆个人主页🎆🎆🎆
🎆🎆🎆JavaEE专栏🎆🎆🎆
🎆🎆🎆计算机是怎么工作的🎆🎆🎆'

文章目录

1.进程

1.1进程的概念

进程是计算机中程序执行的一个实例,是操作系统进行资源分配和调度的基本单位。每个进程都拥有独立的虚拟地址空间、执行状态、寄存器集合等,是操作系统执行多任务的基础.

1.2为什么需要多进程

在现在这个时代,动不动就是8核16线程的CPU甚至更大的CPU,不像以前一个CPU只有一个核心,但是任务又多,核心数又少,导致效率很低,但现在核心数变多了,那么任务就可以同时在多个核心下一起运行就引出了多进程的概念.

1.3多进程的坏处

每创建一次进程就需要系统分配资源(内存资源和文件资源),进程结束之后需要系统去释放资源,如果出现频繁的创建进程和结束进程,这样资源消耗巨大会导致系统响应变慢.所以我们需要引进"线程".

2.线程

2.1引入线程的原因

线程(Thread)是一个轻量级进程,与"进程"相比在创建和销毁上的开销更小,主要原因是:一个进程被创建 系统会给进程分配资源,而一个进程可以有多个线程,这些线程不需要独自一个一个被系统分配资源,它们可以共享系统为进程分配的资源,在销毁的时候也只需要销毁进程的资源即可,这样下来减少了创建与销毁的开销,线程不仅共享进程的资源,而且每一个线程都有自己的属性.

2.2线程的属性

1)ID(此处的id与系统中pcb中的id是不一样的,jvm自己单独搞了一套自己的id体系,但是本质上与pcb中的id是一一对应的)

获取方法:getId()

2)名称

获取方法:getName()

3)状态

获取方法:getState()

4)优先级

获取方法:getPriority()

虽然java提供了优先级的接口,但实际上你去修改了优先级,现象也不是很明显,这里的修改只是作为一个参考,具体还是看系统本身

5)是否后台线程

获取方法:isDaemon()

前台线程:前台线程结束了,那么这个线程就结束了,如果有多个前台线程那么等到最后一个前台线程结束了,那么这个线程就结束了

后台线程:后台线程结束了,不会影响整个线程的进度,但前台线程结束了,整个线程就结束了,那么自然后台线程也就结束了

main线程就是前台线程

还有就是像我们自己创建的线程默认情况下也是前台线程,可以通过setDaemon()方法来把线程设置后台线程

后台线程比如有gc(垃圾回收------对内存还有文件资源的回收) 是一个周期性持续执行的线程,不会自己主动结束

这是将前台线程设置为后台线程代码:

java 复制代码
public class Deom7 {
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                System.out.println("打印thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        t1.setDaemon(true);
        t1.start();
    }

}

注意:

nterrupt和isInterruptted方法

Thread.currentThread()这个是一个static方法,这个方法可以获取到当前线程也就是t这个引用

isInterruptted()方法就是线程内置标志位

true 表示线程要终止

false 表达线程要继续执行

调用这个interrupt()方法:

可以将标志位修改位true还可以唤醒sleep等阻塞

但是调用这个方法之后,如果程序中有sleep方法那么不仅仅会唤醒sleep而且还会清除修改的标志位,此处的清除标志位的目的就是将控制权交给程序猿

如果没有sleep,那么就是一个简简单单的修改标志位

6)是否存活

获取方法:isAlive()

jvm提供的Thread类中的线程与系统中的PCB的生命周期是不一样的

当我已经实例化Thread对象的时候,此时的系统还没有创建PCB

当我们执行到了start()方法的时候,系统才创建PCB

7)是否被中断

获取方法:isInterrupted()

2.3线程的代码写法

总共有五种常见的写法:

1.创建Thread子类

创建一个子类继承于Thread类重写父类的run方法

java 复制代码
class MyThread extends Thread {
    @Override
    public void run() {
        while(true) {
            System.out.println("打印Thread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
public class Deom1 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new MyThread();
        t1.start();
       while(true) {
            System.out.println("打印main");
            Thread.sleep(1000);
        }
    }

2.通过实现Runnable接口

实现接口,重写接口中的run方法,这种方法可以解耦合

java 复制代码
class MyRunnable implements Runnable{

    @Override
    public void run() {
        while(true) {
            System.out.println("打印Thread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
public class Deom2 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new MyRunnable());
        t1.start();
        while(true) {
            System.out.println("打印main");
            Thread.sleep(1000);
        }
    }

}

3.创建匿名内部类继承Thread类

java 复制代码
public class Deom3 {
    public static void main(String[] args) throws InterruptedException {
        new Thread() {
            @Override
            public void run() {
                while (true) {
                    System.out.println("打印Thread");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }.start();


        while (true) {
            System.out.println("打印main");
            Thread.sleep(1000);
        }
    }
}

4.创建匿名内部类实现Runnable接口

java 复制代码
public class Deom4 {
    public static void main(String[] args) throws InterruptedException {
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    System.out.println("打印Thread");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }).start();


        while (true) {
            System.out.println("打印main");
            Thread.sleep(1000);
        }

    }


}

5.使用lambda表达式

java 复制代码
public class Deom5 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            while (true) {
                System.out.println("打印thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        t1.start();

        while(true) {
            System.out.println("打印main");
            Thread.sleep(1000);
        }
    }
}

3,4,5这三种方式好处就是代码简洁,坏处就是可读性不高.

此处提到的run方法与start方法;

run方法:作用就是描述一个任务,然后线程实现之后去实现的任务就是这个run方法中描述的任务

start方法:作用就是创建线程和执行线程

2.4Thread构造方法

1)Thread()无参数

2)Thread(Runnable target) 使用Runnable对象创建对象

3)Thread(String name) 创建线程对象,并命名

  1. Thread(Runnable target,String name)使用Runnable对象创建线程对象,并命名

2.5Thread的等待

由于线程的调度是抢占式的,所以在线程的执行顺序有不确定性,我们就需要引用一个join方法来解决。

在哪个线程中调用join方法就哪个线程阻塞等待

比如:在main线程中调用了t1.join,那么就是main线程等待阻塞,等t1线程结束之后,main线程才执行。

join不参数的属于死等,无限制的去等,这样有时候在有些场景不适用,所以还有一个有时间版本的join方法

join(long millis)

例子:

t1.join(10)被main线程调用,如果t1线程让main线程等待超过了10ms,那么main线程就不会继续等待阻塞下去,就会继续执行main线程下面的代码

使用slee控制的式"线程休眠时间 "而不是"两个代码执行的间隔时间"

main线程等t1线程:

java 复制代码
public class Deom8 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });
        t1.start();
        t1.join();
        System.out.println("main线程结束");
    }
}

让t2等t1线程,main线程等t1和t2线程:

java 复制代码
public class Deom9 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            try {
            System.out.println("t1线程结束");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });

        Thread t2= new Thread(() -> {
            try {
                t1.join();
            System.out.println("t2线程结束");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        });


        t1.start();
        t2.start();
        t2.join();
        System.out.println("main线程结束");
    }

}

main线程只等待t1线程3秒,但t1线程需要5秒执行时间,但时间一到main线程也不会等待t1:

java 复制代码
public class Deom10 {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("t1线程结束");
        });

        t1.start();
        t1.join(3000);
        System.out.println("main线程结束");
    }
}

2.6Thread的状态

1.NEW Thread对象有了,但还未调用start系统内部的线程还未创建

2.TERMINATED 线程已经终止了,系统内核中的线程已经销毁,但对象还在

3.RUNNABLE 就绪状态 指这个线程要么已经在CPU中执行,要么随时都可以被CPU调度

4.WAITING 死等进入阻塞

5.TIMED_WAITING 带有时间的等

6.BLOCKED 进行锁竞争的时候产生的阻塞

绘图描述(简化):

相关推荐
Half-up几秒前
C语言心型代码解析
c语言·开发语言
morris1315 分钟前
【SpringBoot】Xss的常见攻击方式与防御手段
java·spring boot·xss·csp
龙哥说跨境22 分钟前
如何利用指纹浏览器爬虫绕过Cloudflare的防护?
服务器·网络·python·网络爬虫
Source.Liu22 分钟前
【用Rust写CAD】第二章 第四节 函数
开发语言·rust
monkey_meng22 分钟前
【Rust中的迭代器】
开发语言·后端·rust
余衫马25 分钟前
Rust-Trait 特征编程
开发语言·后端·rust
monkey_meng29 分钟前
【Rust中多线程同步机制】
开发语言·redis·后端·rust
七星静香30 分钟前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
Jacob程序员31 分钟前
java导出word文件(手绘)
java·开发语言·word
ZHOUPUYU31 分钟前
IntelliJ IDEA超详细下载安装教程(附安装包)
java·ide·intellij-idea