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计算时间

相关推荐
向阳12185 分钟前
Dubbo负载均衡
java·运维·负载均衡·dubbo
Gu Gu Study15 分钟前
【用Java学习数据结构系列】泛型上界与通配符上界
java·开发语言
WaaTong38 分钟前
《重学Java设计模式》之 原型模式
java·设计模式·原型模式
m0_7430484438 分钟前
初识Java EE和Spring Boot
java·java-ee
AskHarries40 分钟前
Java字节码增强库ByteBuddy
java·后端
小灰灰__1 小时前
IDEA加载通义灵码插件及使用指南
java·ide·intellij-idea
夜雨翦春韭1 小时前
Java中的动态代理
java·开发语言·aop·动态代理
程序媛小果1 小时前
基于java+SpringBoot+Vue的宠物咖啡馆平台设计与实现
java·vue.js·spring boot
追风林1 小时前
mac m1 docker本地部署canal 监听mysql的binglog日志
java·docker·mac
芒果披萨2 小时前
El表达式和JSTL
java·el