java之多线程 莫道桑榆晚,为霞尚满天

多线程

并发与并行

并发:多个指令在单个CPU上交替执行,CPU在多个线程之间切换。

并行:多个指令在多个CPU上同时执行。

多线程的实现

定义类,继承Thread类

重写 run()方法

新建对象 使用start()开启线程

typescript 复制代码
public class MyThread extends Thread{
    @Override
    public void run() {
        super.run();
        System.out.println("hello");
    }

    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.setName("T1");
        myThread.start();
    }
}

声名实现Runable接口的类

java 复制代码
public class MyThread02 implements Runnable{
    @Override
    public void run() {
        Thread thread = Thread.currentThread();
        System.out.println(thread.getName()+ "hello,Runable");
    }

    public static void main(String[] args) {
        MyThread02 myThread = new MyThread02();

        Thread t1 = new Thread(myThread);
        t1.setName("T1");
        t1.start();
    }
}

实现Callable接口

特点:可以获取到多线程运行结果

步骤:

创建类实现Callable接口

重写call方法

使用Futher接口实现类FutherTask管理多线程运行结果

创建Thread,FutherTask对象作为入参。

java 复制代码
//Callable<Integer>  表示返回结果数据类型
public class MyThread03 implements Callable<Integer> {
    @Override
    public Integer call() throws Exception {
        return 100;
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyThread03 mc = new MyThread03();
        FutureTask<Integer> ft = new FutureTask<>(mc);
        Thread thread = new Thread(ft);
        thread.start();
        Integer integer = ft.get();
        System.out.println(integer);

    }
}

三种方式总结:

继承Thread,可扩展性差,不能再继承其他类

实现Run able接口,编程复杂,不可直接使用Thread类中方法。

实现Callable接口, 可以获取到多线程运行结果

守护线程

setDaemon

当非守护线程执行完毕后,守护线程会陆续结束。

Join()插入/队线程

线程生命周期

#黑马截图

线程安全问题

同步代码块Synchronized

Synchronized() 锁对象必须是唯一的

例如 ;.class 、静态对象

同步方法Synchronized 修饰

特点:锁住方法里所有代码

锁对象不能自己指定

非静态方法 this 方法调用者

静态方法 当前类字节码文件对象

Lock(接口)锁

特点:支持手动获取锁、释放锁

csharp 复制代码
public class Lock01 extends Thread{
   static int ticket = 0;
   //共享一把锁
  static Lock lock = new ReentrantLock();

   @Override
   public void run() {
      while (true){
          try {
              lock.lock();
              if(ticket == 100) break;
              else {

                  Thread.sleep(10);
                  ticket++;
                  System.out.println(getName()+"卖第"+ticket+"张票!!");
              }
          }catch (Exception e){
           e.printStackTrace();
          }finally {
              lock.unlock();
          }
      }
   }
测试
   public static void main(String[] args) {
       Lock01 t1 = new Lock01();
       Lock01 t2 = new Lock01();
       Lock01 t3 = new Lock01();
       t1.setName("窗口一");
       t2.setName("窗口二");
       t3.setName("窗口三");

       t2.start();
       t3.start();
       t1.start();
   }
}

等待唤醒机制

生产者消费者

图片来源于黑马,啊伟老师yyds

案列:

公共 复制代码
public class Desk {

    //0没有事物
    public static int flag = 0;
    //总数
    public static int count = 10;
    //锁对象
    public static Object lock = new Object();
}
Food生产 复制代码
public class Food extends Thread {

    @Override
    public void run() {
        while (true) {
            synchronized (Desk.lock) {
                if (Desk.count == 0){
                    break;
                }
                else {
                    if (Desk.flag == 0) {
                        try {
                            Desk.lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    } else {
                        Desk.count--;
                        //唤醒生产者
                        System.out.println("第"+Desk.count+"吃完了");
                        Desk.lock.notifyAll();
                        Desk.flag = 0;
                    }
                }

            }
        }
    }
}
消费 复制代码
public class Cook extends Thread{
    @Override
    public void run() {
        while (true){
            synchronized (Desk.lock){
                if(Desk.count == 0){
                    break;
                }else {
                    //判断桌子有实物
                    if(Desk.flag == 1){
                        try {
                            Desk.lock.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }else {
                        //生产
                        System.out.println("面条做好了");
                        Desk.flag = 1;
                        Desk.lock.notifyAll();

                    }

                }
            }
        }
    }
}

阻塞队列模式

ArrayBlockingQueue

底层是数组,有界

LinkedBlockingQueue

底层是链表,无界不是真正的无界,最大为int最大值

案列

cook 复制代码
public class cook extends Thread{
    ArrayBlockingQueue<String> queue;
    public cook(ArrayBlockingQueue<String> queue) {
        this.queue = queue;
    }
    @Override
    public void run() {
        while (true){
            try {
                queue.put("面条");
                System.out.println("生产了一碗面条");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
food 复制代码
public class Food extends Thread{

    ArrayBlockingQueue<String> queue;

    public Food(ArrayBlockingQueue<String> queue) {
        this.queue = queue;
    }

    @Override
    public void run() {
        while (true){
            try {
                queue.take();
                System.out.println("吃了一碗面条");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
arduino 复制代码
public class Test {
    public static void main(String[] args) {
        ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(2);
        cook cook = new cook(queue);
        Food food = new Food(queue);
        cook.start();
        food.start();
    }

java多线程的六种状态

Thread.State (Java Platform SE 8 )

没有运行态,交给操作系统了。

  • 线程状态。 线程可以处于以下状态之一:

    • NEW
      尚未启动的线程处于此状态。
    • RUNNABLE
      就绪态 start
    • 在Java虚拟机中执行的线程处于此状态。
    • BLOCKED
      被阻塞等待监视器锁定的线程处于此状态。
    • WAITING
      正在等待另一个线程执行特定动作的线程处于此状态。
    • TIMED_WAITING
      计时等待sleep
    • 正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。
    • TERMINATED
      已退出的线程处于此状态。

抽红包案例

ini 复制代码
public class MyThread extends Thread{
    public static double money = 100;
    public static int count = 3;
    public static final double MIN = 0.01;

    @Override
    public void run() {
        synchronized(MyThread.class){
           // 判断共享数据是否到了末尾(到了)
            if(count == 0){
                System.out.println(getName() + "没有抢到红包");
            }else {
                //判断共享数据是否到了末尾(未到)
                double prize = 0;
                //第三次从 剩余全部
                if(count == 1){
                    prize = money;
                }else {
                    //第一、二次从 100随机
                    Random random = new Random();
                    //第一个红包最大 99.98
                    double max = money - (count - 1) *  MIN;
                    //随机数  JDk17及以上
                    prize = random.nextDouble(max);
                    //最小 不能小于 0.01
                    if(prize<MIN){
                        prize = MIN;
                    }
                }
              money =  money - prize;
                count--;
                System.out.println(getName() +"抢到了"+prize);
            }
        }
    }

线程池

使用Executors工具类

两个方法

newCachedThreadPool 创建没有上限的线程池

newFixedThreadPool 指定上限

底层使用ThreadPoolExecutor创建线程池

原理:

新创建的线程池,池子中是空的。

提交任务时,池子会创建新的线程对象,任务执行完,线程回归到线程池。

自定义线程池

ThreadPoolExecutor 定义线程池的类

知识解读:

核心线程

临时线程

队伍长度

什么时候调用临时线程? 当核心线程全部在执行任务,且排队的任务数量已满,就会创建临时线程

如果,核心线程、临时线程、队伍长度都达到最大值,还有任务怎么办? 触发任务拒绝策略

java默认任务拒绝策略

丢弃任务并抛出RejectedExecutionException异常

#黑马截图

实现

ThreadPoolExecutor(int corePoolSize, 核心线程数

int maximumPoolSize, 最大线程数,不小于0,>=核心线程数

long keepAliveTime, 空闲线程最大存活时间 (临时线程)

TimeUnit unit, 时间单位

BlockingQueue workQueue, 任务队列

ThreadFactory threadFactory) 线程工厂

创建一个新的 ThreadPoolExecutor与给定的初始参数和默认拒绝策略执行处理程序。

最大并行数

电脑8核16线程 表示8个CPU

但是inter发明了超线程技术,能够将8个CPU虚拟成16个,就能并行处理16个任务。

最优线程池大小计算

CPU密集型运算 最大并行数 + 1

+1原因,作为候补线程,如果已有线程出现故障,顶替故障线程
I/O密集型运算 读取数据库较多

使用thread dump工具来分析CPU计算时间

相关推荐
风象南几秒前
SpringBoot 控制器的动态注册与卸载
java·spring boot·后端
我是一只代码狗27 分钟前
springboot中使用线程池
java·spring boot·后端
hello早上好39 分钟前
JDK 代理原理
java·spring boot·spring
PanZonghui44 分钟前
Centos项目部署之Java安装与配置
java·linux
沉着的码农1 小时前
【设计模式】基于责任链模式的参数校验
java·spring boot·分布式
Mr_Xuhhh1 小时前
信号与槽的总结
java·开发语言·数据库·c++·qt·系统架构
纳兰青华2 小时前
bean注入的过程中,Property of ‘java.util.ArrayList‘ type cannot be injected by ‘List‘
java·开发语言·spring·list
coding and coffee2 小时前
狂神说 - Mybatis 学习笔记 --下
java·后端·mybatis
千楼2 小时前
阿里巴巴Java开发手册(1.3.0)
java·代码规范
reiraoy2 小时前
缓存解决方案
java