多线程学习笔记

本文是关于Java多线程的学习笔记,详细介绍了进程与线程的概念、线程状态,以及多线程编程的应用场景。还深入探讨了Java并发编程,包括线程的创建方式、线程池、锁机制、并发容器如BlockingQueue,以及Fork/Join框架和CompletableFuture等高级特性。此外,还讨论了并发编程中常见的问题,如虚假唤醒、死锁以及同步工具类的使用。
摘要由CSDN通过智能技术生成

多线程学习笔记

多线程基础

一、进程与线程

1.1 进程与线程的概念

  • 进程是计算机的程序关于某数据集合的一次运行活动

  • 进程是资源分配的最小单位,线程是资源调度的最小单位

  • 线程是进程中一个独立的执行流

**进程和程序:**程序是指令、数据及其组织形式的描述,进程是程序的实体

1.2 线程状态

线程状态图:

在这里插入图片描述

五个状态:

  • 新建:new创建后到start方法前
  • 就绪:调用start方法后就是处于就绪态
  • 运行:获取CPU资源,执行run方法,此时就是运行态
  • 阻塞:
    • 同步阻塞:synchronized获取同步锁失败阻塞
    • 等待阻塞:执行wait方法后
    • 其他阻塞:sleep,join方法执行后
  • 死亡:线程执行结束,或其他条件终止

二、多线程

2.1 概念区分

并发与并行:

  • 并发:一个时间段内,几个任务同时进行。
  • 并行:同一时间点,几个任务同时进行,必要条件:多核,多处理器。

同步与异步:

  • 同步:任务有序执行,一个任务执行完,再执行下一个任务。
  • 异步:几个任务独立执行,执行一个任务的同时也可以执行另一个任务。

异步与多线程:

  • 异步是目的,多线程是实现异步的一种手段

什么是多线程:

  • 是指从软件或者硬件上实现多个线程并发执行的技术

2.2 多线程编程应用场景

  • 高并发
  • 处理大任务:分步上传,分步计算
  • 耗时操作
  • 低优先级定时操作:垃圾回收

三、线程编程

3.1 线程的创建方式

  • 继承Thread类:

    • 重写run方法
  • 实现Runnable接口:

    • 重写run方法
    • 将Runnable交给Thread执行
  • Callable接口和FutureTask

    • 基于委托的适配器模式(FutureTask适配Runnable和Callable)
    • 将FutureTask(Runnable)交给Thread执行
  • 线程池

    • 将Runnable交给线程池的execute方法执行
public class ThreadTest {
   
    public static void main(String[] args) {
   
        //方式1 Thread
        MyThread myThread = new MyThread("w");
        myThread.start();
        //方式2 Runnable
        MyRunnable myRunnable = new MyRunnable();
        new Thread(myRunnable,"我的线程2").start();
        //方式3 Callable和FutureTask
        MyCallable myCallable = new MyCallable();
        FutureTask<Integer> futureTask = new FutureTask<>(myCallable);
        new Thread(futureTask,"我的线程3").start();
        //方式4 线程池
        ThreadPoolExecutor threadPool = new ThreadPoolExecutor(2, 5, 2L, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());
        threadPool.execute(myRunnable);
    }
}

class MyThread extends Thread {
   
    public MyThread(String name) {
   
        super(name);
    }
    @Override
    public void run() {
   
        System.out.println("我的线程");
    }
}
class MyRunnable implements Runnable {
   
    @Override
    public void run() {
   
        System.out.println("创建可执行任务");
    }
}
class MyCallable implements Callable {
   
    @Override
    public Integer call() throws Exception {
   
        System.out.println("创建MyCallable");
        return 1;
    }
}

3.2 线程优先级

Java线程优先级是整数,范围(Thread.MIN_PRIORITY )1 —(Thread.MAX_PRIORITY )10,默认优先级 NORM_PRIORITY(5)。

更改优先级

  • setPriority(int newPriority)

3.3 关键字和方法讲解

关键字

  • volatile:变量可见,防止指令重排
  • synchronzied:同步悲观锁
    • 修饰普通方法:锁当前对象
    • 修饰静态方法:锁类对象
    • 修饰同步方法块:锁synchronized括号里配置的对象

方法

  • wait:
    • 是对象进入等待态,同步阻塞
    • wait会释放锁,出现中须定义同步锁
  • notify:随机唤醒等待队列中持有相同锁的对象
  • notifyAll:唤醒所有等待队列中持有相同锁的对象
  • sleep:线程休眠
  • join:让调用方法的线程加入到当前线程,顺序执行
  • yield:让步,让相同或更高优先级的线程执行
  • interrupt:设置线程中断标志位为true
    • interrupt可以的打断sleep,wait,join使其抛出异常
  • interrupted:返回中断状态,并清除中断状态
  • isInterrupted:返回中断状态,不清除中断状态

问题:

volatile原理:

将变量的修改直接写入主存中,保证各个线程对于变量的可见性。

sleep方法和wait方法:

  • sleep是Thread类的静态方法,wait是Object的实例方法
  • sleep不会释放锁,wait会释放锁
  • wait用于同步代码块,sleep不需要写在同步代码块中interrupt唤醒
  • wait作用与对象,sleep作用于线程

为什么wait方法是Object类

  • 简单来说,Java中锁的级别是对象,由对象本身(共享资源本身)来持有锁。

3.3 线程停止方式

  • 运行完停止

  • 自定义中断标志符

    使用volatile修饰一个变量作为标识

    volatile boolean flag = false;
    
    Thread t = new Thread(()->{
         
       while (true) {
         
           System.out.println("hello");
           if (flag) {
         
               System.out.println("线程结束");
               break;
           }
       }
    });
    t.start();
    Thread.sleep(1000);
    flag = true;
    
  • interrupt

    使用interrupt和isInterrupted使线程停止。

    Thread t = new Thread(()->{
         
       while (!Thread.currentThread().isInterrupted()) {
         
           System.out.println("hello");
       }
    });
    t.start();
    Thread.sleep(1000);
    t.interrupt();
    

3.4 多线程编程步骤

  • 创建资源类,在资源类创建属性和操作方法
  • 在资源类操作方法
    • 判断
    • 干活
    • 通知
  • 创建多个线程,调用资源类的操作方法
  • 防止虚假唤醒

3.5 生产者消费者模式

public class ConsumerProducer {
   
    public static void main(String[] args) {
   
        Buffer buffer = new Buffer(5);
        Producer producer = new Producer(buffer);
        Consumer consumer = new Consumer(buffer);
        new Thread(producer).start();
        new Thread(consumer).start();
    }
}
//资源类
class Buffer {
   
    private Queue<Integer> queue;
    private int size;

    public Buffer(int size) {
   
        this.queue = new LinkedList<Integer>();
        this.size = size;
    }

    public synchronized void add(int i) throws InterruptedException {
   
        //判断
        while (queue.size() >= size) {
   
            wait();
        }
        //干活
        queue.add(i);
        System.out.println("生产者生成了:"+i);
        //通知
        notifyAll();
    }

    public synchronized int get() throws InterruptedException {
   
        while (queue.isEmpty(
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值