• 多线程基础


    多线程基础

    线程基础

    • 程序是指令和数据的有序集合

    • 进程是执行程序的一次执行过程,是一个动态的概念

    • 一个进程包含多个线程,线程是cpu调度和执行的单位

    • plus:

      1. 很多多线程都是模拟出来的,真正的多线程是指有多个cpu,即多核。如果是模拟出来的多线程,即在一个cpu的情况下,在同一个时间点,cpu只能执行一个代码,因为切换的很快,所以就有同时执行的错觉。
      2. 在程序运行时,即使自己没有创建线程,后台也会有多个线程,如主线程,gc线程。
    守护线程
    • 线程分为用户线程和守护线程

    • 虚拟机笔必须确保用户线程执行完毕

    • 虚拟机不用等待守护线程执行完毕

    • 守护线程有如:后台记录操作日志,监控内存,垃圾回收等待

    • 代码实现:thread.setDaemon(true);

    线程实现(重点)

    Thread class->继承Thread类

    Runnable接口(重点)–>实现Runnable接口

    Callable接口–>实现Callable接口

    new Thread.run(); 不会在主线程另开一个子线程去执行,只会继续由主线程去执行

    new Thread.start();会在当前主线程中另开一个子线程去执行,相当于多线程了

    Thread类:
    • 编写自定义线程继承Thread类

    • 重写run()方法,编写线程执行体

    • 创建对象

    • 不建议使用:避免oop单继承局限性

    • /**
       * @author 王顺
       * @description:
       * @date 2022/8/12
       */
      public class TestThread extends Thread{
          @Override
          public void run() {
              for (int i = 0; i < 20; i++) {
                  System.out.println("ws" + i);
              }
          }
      
          public static void main(String[] args) {
              //主方法
              new TestThread().start();
              for (int i = 0; i < 20; i++) {
                  System.out.println("主线程的read" + i);
              }
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
    Runnable接口
    • 自定义MyRunnable类实现Runnbale接口

    • 实现run方法,编写线程执行体

    • 创建线程对象,调用start方法启动线程

    • 推荐使用:避免单继承局限性,方便同一个对象被多个线程使用

    • /**
       * @author 王顺
       * @description
       * @date 2022/8/12
       */
      public class ThreadRunnable implements Runnable{
          @Override
          public void run() {
              for (int i = 0; i < 20; i++) {
                  System.out.println(Thread.currentThread().getId() + i);
              }
          }
      
          public static void main(String[] args) {
              //创建runnable接口的实现类对象
              ThreadRunnable runnable = new ThreadRunnable();
              //创建线程对象,通过线程对象来开启我们的线程,代理
              new Thread(runnable).start();
          }
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
    callable接口–了解即可
    • 实现callable接口,需要返回值类型
    • 重写call方法,需要抛出异常
    • 创建目标对象
    • 创建执行服务:ExecutorService ser=Executors.new FixedThreadPool(1);
    • 提交执行:Future result1=ser.submit(1);
    • 获取结果:boolean r1=result1.get()
    • 关闭服务:ser.shutDownNow();

    线程状态

    • 创建状态–new Thread()后即创建
    • 就绪状态–new Thread().start()后即就绪
    • 阻塞状态
    • 运行状态–从就绪到运行得看cpu心情,心情好给他分配资源
    • 死亡状态

    image-20220812163228157

    线程的State方法–线程观测

    image-20220812171921900

    package com.state;
    
    /**
     * @author 王顺
     * @description
     * @date 2022/8/12
     */
    public class StateTest {
        public static void main(String[] args) throws InterruptedException {
            Thread thread=new Thread(()->{
            for (int i = 0; i < 100; i++) {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
                System.out.println("//");
            });
    
            System.out.println("new之后,state=" + thread.getState());
    
            thread.start();
            System.out.println("start之后,state=" + thread.getState());
    
            while (thread.getState() != Thread.State.TERMINATED) {
                Thread.sleep(100);
                System.out.println(thread.getState());
            }
        }
    }
    
    //结果:
    
    new之后,state=NEW
    start之后,state=RUNNABLE
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    RUNNABLE
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    RUNNABLE
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    RUNNABLE
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    TIMED_WAITING
    RUNNABLE
    //
    TERMINATED
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    线程的stop方法

    image-20220812163938408

    线程的yield方法

    image-20220812170405546

    • 礼让不一定成功的解释:
      • 现在有AB两个线程,a先进入cpu,b等待,现在对a执行yield让a从运行态转成就绪态,这个时候还是ab两个线程在等待,所以这时谁会进入Cpu还是未知,可能又是a进去哦
    线程的join方法
    package com.join;
    
    /**
     * @author 王顺
     * @description:测试join方法
     * @date 2022/8/12
     */
    public class JoinTest implements Runnable{
    
        @Override
        public void run() {
            for (int i = 0; i < 1000; i++) {
                System.out.println("线程vip来了" + i);
            }
        }
    
        public static void main(String[] args) throws Exception{
            JoinTest jt = new JoinTest();
            //子线程
            Thread thread = new Thread(jt);
            thread.start();
    
            //主线程
            for (int i = 0; i < 1000; i++) {
                if (i == 600) {
                    System.out.println("子线程开始插队了");
                    thread.join();//插队
                }
                System.out.println("主线程运行" + i);
            }
        }
    }
    
    //在主线程输出600之前,两个交叉输出,600之后,等子线程剩下的全部执行完毕,才执行主线程
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    线程同步(重点)

    核心实现就是:队列+锁

    具体方法就是:synchronized关键字–Synchronized方法和synchronized块

    synchronized
    • 这里最最重要的就是,你要锁什么?锁住的到底是什么?
    lock与ReentrantLock(可重入锁)
    • 从jdk5.0开始,Java提供了更强大的线程同步机制–通过显示定义同步锁对象来实现同步,同步锁使用Lock对象
    • ReentrantLock类实现了Lock,它拥有与Synchronized相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以显示加锁,释放锁。
    synchronized和lock对比

    Lock是显示锁(手动开启和关闭),synchronized是隐式锁,出了作用域自动释放

    Lock只有代码块锁,synchronized有代码块锁和方法锁

    使用lock锁,jvm将花费较少的时间来调度线程,性能更好

    优先使用顺序–:Lock > 同步代码块 >同步方法

    线程通讯问题

    步锁使用Lock对象

    • ReentrantLock类实现了Lock,它拥有与Synchronized相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以显示加锁,释放锁。
    synchronized和lock对比

    Lock是显示锁(手动开启和关闭),synchronized是隐式锁,出了作用域自动释放

    Lock只有代码块锁,synchronized有代码块锁和方法锁

    使用lock锁,jvm将花费较少的时间来调度线程,性能更好

    优先使用顺序–:Lock > 同步代码块 >同步方法

    线程通讯问题

    线程池

  • 相关阅读:
    17_数据结构与算法
    修改Windows的git bash的主题(样式)
    一文了解Python中的while循环语句
    Node.js中的异步API
    Comparator.nullsLast 处理空值
    String(二)————迭代器及相关接口使用
    项目问题参考答案
    『computed 不生效的坑』
    java基于Springboot+Vue的校园兼职平台大学生求职招聘系统 elementui前后端分离
    leetcode:1562. 查找大小为 M 的最新分组【模拟 + 端点记录 + 范围合并】
  • 原文地址:https://blog.csdn.net/cxywangshun/article/details/126345275