Java多线程

多线程编程

本章目标

  • 掌握线程的基本概念
  • 掌握线程与进程的区别
  • 重点掌握线程的实现方式
  • 掌握线程的管理
  • 掌握线程的生命周期
  • 重点掌握线程同步
  • 重点掌握线程池
  • 掌握线程通信
  • 掌握线程定时器

什么是进程

进程就是正在运行的程序,它是系统进行资源分配和调度的基本单位,各个进程之间相互独立,系统给每个进程分配不同的地址空间和资源

image-20210802095954225

Win 操作系统任务管理器查看应用程序运行的进程

什么是线程

线程就是程序(进程)执行的任务(分为单线程和多线程)

image-20210802100059707

进程与线程的区别

地址空间

进程之间是独立的地址空间,但同一进程的线程共享本进程的地址空间

资源占用

同一进程内的线程共享本进程的资源,如内存、I/O、CPU 等,但是进程之间的资源是独立的

健壮性

一个进程崩溃后不会对其他进程产生影响;一个线程崩溃则整个进程都死掉,所以多进程要比多线程更健壮

执行过程

进程可以独立执行,线程不能独立执行,线程必须依存于进程

并发与资源消耗

进程和线程都可以并发(同时)执行,但进程创建和切换消耗资源大,线程创建和切换消耗资源小

创建线程

方式一:继承 Thread 类,并重写 run( ) 方法
public class MyThread extends Thread {   
   public void run() {  
         for ( int i = 0; i < 10; i++ )  {  
             System.out.println(“子线程");  
         }  
   }  
   public static void main(String[] args) {  
         MyThread myThread = new MyThread(); 
         myThread.start();  
         for ( int i = 0; i < 10; i++ ) {  
             System.out.println(“主线程");           }  
   } 
}
方式二:实现 Runnable 接口,并实现 run( ) 方法
public class MyThread implements Runnable {   
   public void run() {  
         for ( int i = 0; i < 10; i++ )  {  
             System.out.println(“子线程");  
         }  
   }  
   public static void main(String[] args) {  
         MyThread myThread = new MyThread(); 
         myThread.start();  
         for ( int i = 0; i < 10; i++ ) {  
             System.out.println(“主线程");           }  
   } 
}

线程的状态

当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。在线程的生命周期中,它要经过新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Dead)5种状态。尤其是当线程启动以后,它不可能一直"霸占"着CPU独自运行,所以CPU需要在多条线程之间切换,于是线程状态也会多次在运行、阻塞之间切换。

  1. 新建状态:当程序使用new关键字创建了一个线程之后,该线程就处于新建状态,此时仅由JVM为其分配内存,并初始化其成员变量的值

  2. 就绪状态:当线程对象调用了start()方法之后,该线程处于就绪状态。Java虚拟机会为其创建方法调用栈和程序计数器,等待调度运行

  3. 运行状态:如果处于就绪状态的线程获得了CPU,开始执行run()方法的线程执行体,则该线程处于运行状态

  4. 阻塞状态:当处于运行状态的线程失去所占用资源之后,便进入阻塞状态

  5. 死亡状态:当线程的 run() 方法执行完成,线程正常结束或抛出一个未捕获的异常,也可以直接调用 stop() 方法结束线程(容易导致死锁,不推荐使用)

image-20210802100411740

线程暂停执行条件
  • 线程优先级比较低,不能获得 CPU 时间片
  • 使用 sleep( ) 方法使线程睡眠
  • 通过调用 wait( ) 方法,使线程处于等待状态
  • 通过调用 yield( ) 方法,线程主动出让 CPU 控制权
  • 线程由于等待一个I/O事件处于阻塞状态
线程优先级

Java 中线程优先级是在 Thread 类中定义的常量

  • NORM_PRIORITY : 值为 5

  • MAX_PRIORITY : 值为 10

  • MIN_PRIORITY : 值为 1

缺省优先级为 NORM_PRIORITY

修改和查看线程优先级方法

  • final void setPriority(int newPriority) //修改当前线程的优先级

  • final int getPriority()//查看当前线程的优先级

多线程

多线程并发问题

image-20210802100639790

线程 A 和线程 B 同时操作(读写)同一进程下的共享资源,这将导致数据不一致的问题,被称为多线程并发问题。

线程同步

多线程共享数据时,可能会发生数据不一致的情况,而线程同步就是为了解决多线程并发问题,它可以确保在任何时间点一个共享的资源只被一个线程使用

实现线程同步的三种方式

  • 使用同步代码块
  • 使用同步方法
  • 使用互斥锁 (更灵活的代码控制)
线程死锁

image-20210802101002998

线程 A 和线程 B 都想访问对方的资源,但都不愿意让对方先访问,这样谁也无法继续执行下去,这就是线程死锁(线程死锁很少发生,但一旦发生就很难调试)

线程池

如果并发的线程数量很多,并且线程执行一个时间很短的任务就结束了,这样就会频繁的创建和销毁线程,导致大大降低系统的运行效率

image-20210915140509073

线程池工作原理
  • 程序启动时向线程池中提前创建一批线程对象
  • 当需要执行任务时,从线程池中获取一个空闲的线程对象
  • 任务执行完毕后,不销毁线程对象,而是将其返还给线程池,并再次将状态设置为空闲
线程池优缺点
  • 减少频繁创建和销毁线程对象的时间消耗,提高了程序运行的性能(优点)
  • 线程池中空闲的线程对象,会占用系统更多的内存存储空间(缺点)

线程池是一种以时间换空间的性能优化策略

Java四种内置线程池

Java 语言提供了一系列线程池的实现,以解决实际开发中各种对线程池的需求

  • newCachedThreadPool
  • newFixedThreadPool
  • newScheduledThreadPool
  • newSingleThreadExecutor
Java 两个基础线程池

如果内置四个线程池实现仍无法满足需求,则 Java 语言还提供了两个基础线程池

  • ThreadPoolExecutor 类
  • ScheduledThreadPoolExecutor 类

这两个基础线程池用于用户创建自定义线程池,以获得更大的灵活度,同时开发难度也更大

线程间通信

wait-notify 机制

线程同步能够解决多线程并发问题,但它没有实现线程间的通信

image-20210802102246501

Java 提供了一个精心设计的线程间通信机制,使用wait()、notify() 和 notifyAll() 方法,这些方法是作为 Object 类中的 final 方法实现的。这三个方法仅在 synchronized 方法中才能被调用

  • wait() 方法:方法告知被调用的线程退出监视器并进入等待状态,直到其他线程进入相同的监视器并调用 notify( ) 方法
  • notify( ) 方法:通知同一对象上第一个调用 wait( )线程
  • notifyAll() 方法:通知调用 wait() 的所有线程,具有最高优先级的线程将先运行

线程定时器

Time 类

Timer是一个普通的类,其中有几个重要的方法

  • schedule() 方法:启动定时器一个定时任务
  • cancel()方法:终止定时器所有定时任务

启动一个定时任务就创建一个线程,线程会一直执行下去,直到调用终止定时任务

TimerTask 类

TimerTask 是一个抽象类,需要实现该类

  • run()方法:定时任务逻辑
//创建一个定时任务
Timer timer = new Timer();
timer.schedule(new TimerTask() {
    @Override
    public void run() {
        // 任务执行代码
    }
}, 5000,1000); //延时 5s 每间隔1s 执行一次
posted @ 2021-09-15 14:11  嘛了对就念来过倒  阅读(45)  评论(0编辑  收藏  举报