likes
comments
collection
share

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

作者站长头像
站长
· 阅读数 30

多线程

并发与并行

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

多线程的实现

定义类,继承Thread类

重写 run()方法 新建对象 使用start()开启线程

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接口的类

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对象作为入参。

//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()插入/队线程

线程生命周期

#黑马截图 java之多线程 莫道桑榆晚,为霞尚满天

线程安全问题

同步代码块Synchronized

Synchronized() 锁对象必须是唯一的 例如 ;.class 、静态对象

同步方法Synchronized 修饰

特点:锁住方法里所有代码 锁对象不能自己指定 非静态方法 this 方法调用者 静态方法 当前类字节码文件对象

Lock(接口)锁

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

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 java之多线程 莫道桑榆晚,为霞尚满天

案列:

public class Desk {

    //0没有事物
    public static int flag = 0;
    //总数
    public static int count = 10;
    //锁对象
    public static Object lock = new Object();
}
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();

                    }

                }
            }
        }
    }
}

阻塞队列模式

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

ArrayBlockingQueue

底层是数组,有界

LinkedBlockingQueue

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

案列

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();
            }
        }
    }
}
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();
            }
        }
    }
}
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 已退出的线程处于此状态。

抽红包案例

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异常

#黑马截图 java之多线程 莫道桑榆晚,为霞尚满天

实现

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密集型运算 读取数据库较多 java之多线程 莫道桑榆晚,为霞尚满天 使用thread dump工具来分析CPU计算时间

转载自:https://juejin.cn/post/7357932616086749235
评论
请登录