Java多线程基础整理

本文详细介绍了Java多线程的基础知识,包括进程与线程的关系、线程状态、创建线程的四种方式(继承Thread类、实现Runnable接口、实现Callable接口、使用线程池)以及线程的常用方法。重点讲解了synchronized关键字的使用、同步处理、线程同步和死锁的概念,还探讨了Lock体系、线程池的使用及其优缺点。此外,还讨论了线程的等待、唤醒和中断机制,以及线程池的配置和内置线程池类型。
摘要由CSDN通过智能技术生成

多线程复习

在这里插入图片描述

1.进程和线程

1.1定义

(1)进程:操作系统中一个程序的执行周期

(2)线程:进程中的一个任务。一个进程中可以包含n个线程(main()->主线程)

1.2进程与线程的关系

  • 每个进程拥有自己的一整套变量,是操作系统中资源分配的最小的单位。

​ 线程依托于进程存在,多个线程共享进程的资源,os中任务调度的基本单位。

  • 启动、撤销一个进程的开销要比启动、撤销以一个线程大的多(线程轻量级
  • 进程间通信远比线程间通信复杂的多;
  • 没有进程就没有线程,进程一旦终止,其内的线程全部取消;

1.3线程的状态

在这里插入图片描述

2.多线程实现

Java中创建线程的四种方式:

(1)继承Thread类

(2)实现Runnable接口

(3)实现Callable接口

(4)使用线程池(推荐

2.1继承Thread类

java.lang.Thread是线程操作的核心类

2.1.1出现版本

JDK1.0

2.1.2实现方法

直接继承Thread类而后覆写类中的run()方法(相当于主方法,一个线程的入口就是run方法)

无论哪种方式实现多线程,线程启动一律调用Thread类提供的start()方法。

2.1.3start()方法解析

1.首先检查线程状态是否为0(线程默认状态为0表示为启动),如果线程已经启动再次调用start()方法会抛出IllegalThreadStateException异常。所以一个线程的start()方法只能调用一次

2.private native void start0();通过start0()方法真正将线程启动

3.JVM调用start0()方法进行资源分配与系统调度,**准备好资源启动线程后回调run()**来执行线程的具体任务!

2.1.4线程启动调用方法流程

start()->start0()->JVM_StartThread()->run_method_name()->run()

2.1.5局限性

单继承问题

2.2实现Runnable接口

java.lang.Runnable

2.2.1出现版本

JDK1.0

2.2.2实现方法

Java中Thread类本身也实现了Runnable接口,与用户自定义的线程类共同组成代理设计模式

其中Thread类实现辅助操作,包括线程的资源调度等任务;自定义线程类完成真实业务·

在这里插入图片描述

实现Runnable接口,覆写run()

public Thread(Runnable target){}

public static void main(String[] args) {
        MyThread1 mt1 = new MyThread1();
        MyThread1 mt2 = new MyThread1();
        MyThread1 mt3 = new MyThread1();
        Thread t1 = new Thread(mt1);
        Thread t2 = new Thread(mt2);
        Thread t3 = new Thread(mt3);
        t1.start();
        t2.start();
        t3.start();
}
2.2.3继承Thread类与实现Runnable接口区别
  • 继承Thread类有单继承局限,相对而言实现Runnable接口更加灵活,并且Thread类本身也实现了Runnable辅助真实业务类
  • 实现Runnable接口可以更好的实现程序共享的概念(Thread类也可以,)

2.3实现Callable接口

java.util.concurrent

2.3.1出现版本

JDK1.5

2.3.2实现方法

实现Callable接口,覆写call()方法

Future:可接收call()方法的返回值

在这里插入图片描述

public static void main(String[] args) throws ExecutionException, InterruptedException {
        //1.产生Callable对象
        MyThread3 mt = new MyThread3();
        //2.产生FutureTask对象
        FutureTask<String> ft = new FutureTask<>(mt);
        new Thread(ft).start();
        new Thread(ft).start();
        new Thread(ft).start();
        //3.接收call()返回值,FutureTask的get()继承自Future接口中的get()
        System.out.println(ft.get());
}
2.3.3实现Runnable接口与实现Callable接口的区别
  • 实现Callable接口,线程执行任务后有返回值;而实现Runnable接口,线程执行后没有返回值

3.多线程常用方法

3.1线程的命名与取得

  • 取得当前JVM正在执行的线程对象:public static native Thread currentThread();
  • 线程命名:
    • 创建线程时设置名称:public Thread (Runnable target,String name)
    • 设置线程名称:public final synchronized void setName(String name)
  • 取得线程名:public final String getName()

3.2线程休眠

3.2.1定义

让线程暂缓执行,等到了预计时间再回复执行

public static native void sleep(long millis) throws InterruptedException{};

3.2.2状态变换

运行状态---->阻塞状态---->休眠结束---->就绪状态

3.2.3注意

(1)线程休眠会立即交出CPU,让CPU去执行其他任务。线程休眠不会释放对象锁

(2)多个线程进入一个方法,不是同时休眠的;

3.3线程让步

3.3.1定义

暂停当前正在执行的线程对象,并执行其他线程

public static native void yield();

3.3.2状态变换

运行状态<---->就绪状态

3.3.3注意

(1)yield()会让当前线程交出CPU,但不一定会立即交出。yield()交出CPU后只能让拥有相同优先级的线程有获取CPU的机会不会释放对象锁

3.4线程等待

3.4.1定义

等待该线程终止。

若线程1需要等待线2执行完毕后再恢复执行,可以在线程1中调用线程2的join();在哪个线程调用,哪个线程阻塞,等待线程执行完毕再恢复执行

3.4.2状态转换

运行状态->阻塞状态->就绪状态

3.4.3注意

(1)join()方法只是对Object类wait()做了一层包装而已;

(2)交出cpu,释放对象锁

3.5线程停止

3.5.1三种方式停止线程
  • 设置标记位,可以使线程正常退出(推荐)

  • 使用stop方法强制让线程退出,但是该方法不安全已经被@Deprecated

  • 使用Thread类提供的interrupt()中断线程(就是系统设置了一个标记位,直接使用即可)

    interrupt方法只是将线程状态改为中断状态而已,它不会中断一个正在运行的线程;

3.5.2设置标记位
class MyThread02 implements Runnable{
    private int books = 0;
    private boolean flag = true;

    public void setFlag(boolean flag) {
        this.flag = flag;
    }

    @Override
    public void run() {
        while (flag == true){
            System.out.println(Thread.currentThread().getName()+"卖出书号:"+(books--));
        }
        System.out.println("线程停止");
    }
}

public class test02 {
    public static void main(String[] args) throws InterruptedException {
        MyThread02 mt1 = new MyThread02();
        Thread t1 = new Thread(mt1);
        t1.start();
        Thread.sleep(1000);
        mt1.setFlag(false);
    }
}
3.5.3stop方法

强行关闭线程,不管有没有执行完循环(不推荐使用)

废弃的原因:不安全,stop()会解除由线程获得的所有锁定,当在一个线程对象上调用了stop(),这个线程对象所运行的线程就会立即停止,可能会产生不完整数据信息

3.5.4interrupt()方法

调用interrupt()

  • 如果在线程中没有调用wait() sleep() join(),则标记线程(isInterrupt = true);

    并不会真正中断线程,只是简单的将线程的状态置为interrupt而已,我们可以根据此状态来进一步确定如何处理线程;

    Thread类提供的public boolean isInterrupted()可以检测当前线程状态是否为中断状态

  class MyThread1 implements Runnable{
      boolean flag = true;
      @Override
      public void run() {
          int i = 0;
          while (flag){
              boolean bool = Thread.currentThread().isInterrupted();
              if(bool){
                  System.out.println("线程进入中断状态");
                  return;
              }
              System.out.println("当前线程状态为"+bool);
              System.out.println(Thread.currentThread().getName()+","+(i++));
          }
          System.out.println("线程停止");
      }
  }
  
  public class threadInterrupt {
      public static void main(String[] args) throws InterruptedException {
          MyThread1 mt1 = new MyThread1();
          Thread thread = new Thread(mt1);
          thread.start();
          Thread.sleep(1000);
          thread.interrupt();
      }
  }

一秒后设置线程状态为中断状态,调用isInterrupt()返回值为true,进入if语句,执行操作,输出线程进入中断状态&#

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值