美文网首页
多线程基础

多线程基础

作者: _一叶孤帆 | 来源:发表于2021-01-31 23:22 被阅读0次

    基础概念

    什么是线程和进程

    线程

    线程是 CPU 调度的最小单位,不能独立于进程存在,可以共享进程中的资源。

    进程

    操作系统进行资源分配的最小单位。资源指的就是内存空间、磁盘IO...
    进程与进程之间是相互独立的。

    CPU 核心数和线程数的关系

    物理核心数:

    物理 CPU 就是计算机上实际配置的 CPU 个数。

    CPU 核数:

    单块 CPU 上面能处理数据的芯片组的数量,如双核bai、四核等

    逻辑 CPU 数

    操作系统可以使用逻辑 CPU 来模拟出真实 CPU 的效果。在之前没有多核处理器的时候,一个 CPU 只有一个核,而现在有了多核技术,其效果就好像把多个 CPU 集中在一个 CPU 上。
    当计算机没有开启超线程时,逻辑 CPU 的个数就是计算机的核数。而当超线程开启后,逻辑 CPU 的个数是核数的两倍。
    一个物理核心上有多个处理器。

    CPU 总核数 = 物理 CPU 个数 X 每颗物理 CPU 的核数
    CPU 逻辑数 = 物理 CPU 个数 X 每颗物理 CPU 的核数 X 超线程数

    CPU 时间片轮转机制 (RR 调度)

    时间片轮转调度是一种最古老,最简单,最公平且使用最广的算法。每个进程被分配一个时间段,称作它的时间片,即该进程允许运行的时间。

    进程调用会进行上下文切换,损耗性能。

    并行和并发

    并行

    可以同时运行的任务数。

    并发

    并发是不能脱离时间单位的,指的是单位时间内能够处理的任务数。

    高并发的意义、好处和注意事项

    好处
    1. 可以充分的利用 CPU 的资源
    2. 加快响应用户的时间
    3. 可以是代码模块化,异步化。
    注意事项
    1. 线程安全问题
    2. 死锁问题
    3. 线程数问题
      • 一个进程在 Linux 中1000/window 中 2000,线程会分配栈空间,会消耗资源。

    Java 线程

    Java 程序本身就是一个多线程的程序。

    
    public class Main {
    
        public static void main(String[] args) {
    
            ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
            ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false, false);
            for (ThreadInfo threadInfo : threadInfos) {
                System.out.println("id + " + threadInfo.getThreadId() + "name + " + threadInfo.getThreadName() + "state + " +threadInfo.getThreadState());
            }
        }
    }
    
    id + [1] : name + mainstate + RUNNABLE
    id + [2] : name + Reference Handlerstate + RUNNABLE
    id + [3] : name + Finalizerstate + WAITING
    id + [4] : name + Signal Dispatcherstate + RUNNABLE
    id + [10] : name + Common-Cleanerstate + TIMED_WAITING
    id + [11] : name + Monitor Ctrl-Breakstate + RUNNABLE
    id + [12] : name + Notification Threadstate + RUNNABLE
    

    新启线程的方式

    两种,在Thread中声明的。

    image.png

    通过类 Thread

    package com.sail;
    
    public class NewThead {
    
        private static class UseThread extends Thread {
            @Override
            public void run() {
                super.run();
                // 做操作
                System.out.println("UseThread:" + Thread.currentThread().getName());
            }
        }
    
        public static void main(String[] args) {
    
            System.out.println("main:" + Thread.currentThread().getName());
    
            UseThread useThread = new UseThread();
            useThread.start();
        }
    }
    
    
    main:main
    UseThread:Thread-0
    

    通过接口Runnable

    package com.sail;
    
    public class NewThreadTwo {
    
    
        private static class UserRunnable implements Runnable{
            @Override
            public void run() {
                //做事情
                System.out.println("UserRunnable:" + Thread.currentThread().getName());
            }
        }
    
        public static void main(String[] args) {
            System.out.println("main:" + Thread.currentThread().getName());
    
            UserRunnable userRunnable = new UserRunnable();
            new Thread(userRunnable).start();
    
        }
    }
    
    main:main
    UserRunnable:Thread-0
    

    区别

    Thread 是对线程的抽象。
    Runnable 是对任务(业务逻辑)的抽象。

    如何让线程安全的停止工作

    stop()

    会导致线程占用的资源不会正常的释放。

    interrupt()

    是对线程进行中断,并不会真正的终止线程,只是给线程一个中断标识(ture),告诉线程该中断了。
    可以说明在 JDK 中,线程是协作式的,并不是抢占式的。

    interrupted()

    判定当前线程是否被中断,监听到 interrupt() 后,会将 中断标识结果为由 true 变成 false

    isInterrupted()

    判定当前线程是否被中断,监听到 interrupt() 后,isInterrupted 结果为 true,其实就是返回了中断标识。

    启动线程

    run()

    run()只是一个成员方法,可以被反复调用,单独调用 run() 并不会启动线程。

    start()

    调用 native 方法启动线程
    如果多次调用 start() 会抛出异常。

    生命周期

    image.png
    yield()

    当前线程让出 CPU 执行权,重新分配 CPU 的占用权,不会让出锁。

    join()

    A 正在执行时,B 调用 join(),A 会让出执行权,等 B 执行完之后再执行。

    Q:如何保证两个线程顺序执行
    A:使用 join() 方法。

    线程的优先级

    setPriority(1); 1 ~ 10 默认为5 
    

    真正能不能发挥作用由操作系统决定。
    不能控制线程的执行顺序。

    守护线程

    处理一些支持性的工作,通过 new thread 启动的线程都是用户线程,非守护线程。由JDK启动或者配置的称为守护线程。

    在一个进程中,所有的非守护线程执行完之后,进程就跟着停止了。

    自己配置守护线程

    线程对象.setDaemon(true);
    

    守护线程中的 finally 不一定起作用,取决于 CPU 分配的时间片是否刚好执行到此线程。

    用户线程的 finally 是一定会执行的。

    synchronized 内置锁

    保证某一个时刻只有一个线程访问某个方法。

    用法

    • 同步块


      image.png
    image.png
    • 方法


      image.png

      其实锁的就是 this 对象。

    对象锁

    上面的用法都是锁的一个对象,叫做对象锁。
    如果同时有多个对象,还是可以存在并行进行。

    类锁

    在 static 方法上加锁的话,锁的是一个 class 对象,虚拟机为每个类加载都会有的唯一的对象。其实也是对象锁,只是锁的 class 类对象。

    错误的加锁

    没有锁的同一个对象,导致发送错误。

    volatile

    最轻量的同步机制,保证的是 可见性

    当一个值在多线程下修改的时候,能够立即同步到其他线程。

    相关文章

      网友评论

          本文标题:多线程基础

          本文链接:https://www.haomeiwen.com/subject/xuudtltx.html