Java中的多线程一

2024-01-09 21:48:39

概述

进程

  • 是正在运行的程序
    • 是系统进行资源分配和调用的独立单位
    • 每一个进程都有它自己的内存空间和系统资源

线程

  • 进程中的单个顺序控制流,是一条执行路径
    • 单线程: 一个进程如果只有一条执行路径,则称为单线程程序
    • 多线程: 一个进程如果有多条执行路径,则称为多线程程序

多线程

线程两种常见实现方式

  • 方法一:将一个类声明为Thread的子类(继承), 这个子类应该重写Thread类的run方法 。 然后可以分配并启动子类的实例。

    • 实现步骤
      1. 定义一个类 MyThread 继承 Thread 类
      2. 在 MyThread 类中 重写 run() 方法
      3. 创建 MyThread 类的对象
      4. 启动线程 start() 导致此线程开始执行,Java 虚拟机调用此线程的 run 方法
    • 示例代码
    class MyThread extends Thread{
        @Override
        public void run() {
            System.out.println("你好!");
        }
    }
    
    public class Test1 {
        public static void main(String[] args) {
            // 创建 MyThread 对象
            MyThread mt = new MyThread();
            // 启动线程
            mt.start();
        }
    }
    

    运行结果:你好!

  • 方法二:声明实现类 Runnable 接口(实现),那个类

    • 实现步骤
      1. 定义一个类 MyRunnable 实现 Runnable 接口
      2. 在 MyRunnable 类中 重写 run() 方法
      3. 创建 MyRunnable 类的对象
      4. 创建 Thread 类的对象,把 MyRunnable 对象作为构造方法的参数
      5. 启动线程 start() 导致此线程开始执行,Java 虚拟机调用此线程的 run 方法
    • 示例代码
    class MyRunnable implements Runnable{
        @Override
        public void run() {
            System.out.println("欢迎来到编程世界!");
        }
    }
    
    public class Test2 {
        public static void main(String[] args) {
            // 创建 线程类对象
            MyRunnable mr = new MyRunnable();
            // 创建 Thread 对象
            Thread t = new Thread(mr);
            // 启动线程
            t.start();
        }
    }
    

    运行结果:欢迎来到编程世界!

  • 问题?

    1. 为什么重写 run() 方法?
      • run() 方法是用来 封装被线程执行的代码,也就是线程要做的任务
    2. run() 方法 和 start() 方法的区别?
      • 直接调用 run() 方法,相当于 main 线程去执行 run() 方法,并无新的线程产生
      • 调用 start() 方法,创建并启动线程,由 JVM 调用 run() 方法
  • 异常 IllegalThreadStateException

    • 同一个线程对象,只能调用一次 start() 方法,不能两次调用,调用两次会,抛出 上述异常。
    • 示例代码
    class MyThread extends Thread{
        @Override
        public void run() {
            System.out.println("你好!");
        }
    }
    
    public class Test1 {
        public static void main(String[] args) {
            // 创建 MyThread 对象
            MyThread mt = new MyThread();
            // 启动线程
            mt.start();
            mt.start();
        }
    }
    
    • 异常演示

    • 为什么会产生上述异常呢?我们来看下 start() 的源码

    • A zero status value corresponds to state “NEW” 意思是 零状态值对应于状态“NEW”

      状态描述
      新建(NEW)表示线程已经创建好了,但是还没有调用 start() 方法
      就绪(RUNNABLE)表示线程可能在运行,也可能在就绪队列
      阻塞(BLOCKED)表示线程处于等在锁的状态
      等待(WAITING)表示线程处于条件等待状态,当触发条件后会唤醒
      计时等待(TIME_WAIT)比 WAITING 多了个超时条件触发的机制
      终止(TERMINATED)表示线程执行结束

      线程第二次调用 start() 方法时,可能处于终止或者其他非 NEW 状态,对线程判断是否处于 NEW 状态,不是,就会抛出异常


两种实现方式的好处?

  • 相比继承 Thread 类,实现 Runnable 接口的好处?
    • 避免了Java单继承的局限性
    • 适合多个相同程序的代码去处理同一个资源的情况,把线程和程序的代码、数据有效分离,较好的体现了面向对象的设计思想

线程执行的随机性

  • 线程执行的随机性,原因是线程"抢占式执行"的方式,谁先抢到,CPU分配资源,谁先执行的缘故。

  • 示例代码

    class MyThread extends Thread{
        private int value;
        public MyThread(int value){
            this.value = value;
        }
        @Override
        public void run() {
            System.out.println(value);
        }
    }
    
    public class Test1 {
        public static void main(String[] args) {
            // 创建 MyThread 对象
            MyThread mt1 = new MyThread(1);
            MyThread mt2 = new MyThread(2);
            MyThread mt3 = new MyThread(3);
            MyThread mt4 = new MyThread(4);
            // 启动线程
            mt1.start();
            mt2.start();
            mt3.start();
            mt4.start();
        }
    }
    
  • 输出结果

    注意:由于随机性,所以运行多次产生的结果是可能不一致的

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