详解线程(一)

发布于:2022-12-20 ⋅ 阅读:(410) ⋅ 点赞:(0)

目录

1.线程的基本概念

进程与线程

2.创建线程

3.串行执行与多线成执行速度对比


1.线程的基本概念

线程是进程中的⼀个执⾏单元,负责当前进程中程序的执⾏,⼀个进程中⾄少有⼀个线程。⼀个进

程中是可以有多个线程的,这个应⽤程序也可以称之为多线程程序。

了解操作系统中的进程后,我们知道多进程实现了并发编程,提高了CPU的利用率

想要了解多线程,就必须弄清楚进程的创建过程:

1.创建一个PCB 

2.给进程分配资源,赋值到PCB中 

3.把PCB插入到链表中

进程销毁: 

1.把PCB从链表上删除

2.把PCB中持有的资源释放

 在这个过程中, 由于频繁的创建和删除进程,给进程分配空间资源消耗大,比较耗时间,就会很低效,为了解决这个问题于是就有了多线程

进程与线程

1. 线程包含在进程里,一个线程个包含多个线程,也可以包含一个线程.同一份进程中的这些线程共用一份资源,这里的资源包括内存和文件.

2.每个线程都是一个"执行流", 可以单独在CPU上进行调度

3.因为创建线程 销毁线程开销比较小,所以线程被称之为"轻量级进程"

缺点:缺点时线程之间会相互影响,当线程足够多的时候,效率无法继续提升,反而影响其他线程.因

为CPU时有限的,CPU核心数已经吃满了,进程的虚拟内存空间上限.

进程相当于工厂,想要扩大生产,就有两个方案,第一就是在创建一个工厂,第二个方案就是在原来的

厂里的空闲位置在设置一个生产线,每个成产线有独立进行生产,而这个生产线的原材料时共享的,

生产好的产品怎么运走,也是现成的,虽然还是这个工厂,但是生产线多了一个,生产效率还是提高了

不少!

区别:

1.进程包含线程

2.线程比进程更轻量,创建更快,销毁也更快

3.同一个进程的多个线程之间共用同一份内存/文件资源,进程与进程之间,则是独立的内存/文件资

4.进程时资源分配的基本单位,线程时调度执行的基本单位

在进程中说到的PCB,其实说的就是操作系统PCB,只不过钱买你没有明确点出,其实每个PCB就是一个线程

2.创建线程

创建线程时,并不是实例一个相关对象就创建了一个线程,想要创建一个线程必须要在该对象的基础上调用start方法,至于这个对象是什么,就要看下文的代码.

线程里有一个run方法,方法里的内容就是这个这个线程要干的事.一个线程最少就有一个线程,就是main线程,称作主线程,如果程序中有多个线程,操作系统调度线程的时候, 是一个随机过程,但不是严格上的数学随机.他们是"抢占式执行",所以线程容易出现各种变数

下面用五种方法创建线程,并证明线程的执行存在随机性

1.继承Thread,重写run方法

class MyThread extends Thread{ //Thread 为标准库对的类,来表示线程
    @Override
    public void run(){   //重写run方法 run就是线程要执行的工作
        while(true){
            System.out.println("hello thread");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

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

2.实现Runnable,重写run方法

class MyRunnable implements Runnable{
    @Override
    public void run(){
        System.out.println("hello thread");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

public class Demo2 {
    public static void main(String[] args) {
        MyRunnable runnable = new MyRunnable();//要完成的工作
        Thread t = new Thread(runnable);//提取出来传给Thread
        t.start();
        while(true){
            System.out.println("hello main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

3. 使用匿名内部类,实现创建Thread子类的方式

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

4.使用内部类,实现Runnable接口的方式

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

5.lambda表达式

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

lambda本质上是一个"匿名函数", ()函数的形参 { }表示函数体,->表示特殊语法表示,表示它是一个lambda表达式.

3.串行执行与多线成执行速度对比

public class Demo6 {
    public static final long COUNT = 1000_000_0000L;
    public static void main(String[] args) {
        concurrency();
    }

    //一个线程串行执行
    public static void serial(){
        long beg = System.currentTimeMillis();

        long a = 0;
        for(long i = 0;i < COUNT; i++){
            a++;
        }
        a = 0;
        for (long i = 0; i < COUNT; i++) {
            a++;
        }
        long end = System.currentTimeMillis();
        System.out.println("执行的时间间隔:" + (end - beg) + "ms");
    }

    //两个线程并发执行
    public static void concurrency(){
        long beg = System.currentTimeMillis();
        Thread t1 = new Thread(() ->{
            long a = 0;
            for (long i = 0; i < COUNT; i++) {
                a++;
            }
        });
        Thread t2 = new Thread(() ->{
            long a = 0;
            for (long i = 0; i < COUNT; i++) {
                a++;
            }
        });

        t1.start();
        t2.start();

        try {
            t1.join();//这里面的join就是阻塞主线程,该线程执行完,主线程才开始继续执行
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        long end = System.currentTimeMillis();
        System.out.println("执行的时间间隔:" + (end - beg) + "ms");
    }
}

运行上诉代码,一个串行线程执行上述程序,单个线程串行执行的代码平均花的时间是5200左右,两个线程并发执行平均花费的时间是2900ms,这个速度不是单纯的两倍的关系,是因为这里的并发执行,实际上是包含"并发"与"并行".当线程采用"并发"执行时,执行的时间并没有变化,只有当采用"并行"执行",这个花费的时间才会减少,所以不是简单的两倍关系.

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到