山东大学软件学院项目实训-创新实训-基于大模型的旅游平台(十五)- JUC(1)

目录

创建线程

方法一:直接使用Thread

方法二:使用Runnable配合Thread

[方法三 :FutureTask配合Thread](#方法三 :FutureTask配合Thread)

线程交替运行

线程运行原理

线程上下文切换

常用方法

start

run

sleep

yield

interrupt

setPriority

join


创建线程

方法一:直接使用Thread

复制代码
  @Slf4j
  public class Test {
      public static void main(String[] args) {
          Thread t = new Thread(){
              @Override
              public void run() {
                  log.debug("aaa");
              }
          };
          t.start();
      }
  }

方法二:使用Runnable配合Thread

复制代码
  
  @Slf4j
  public class Test {
      public static void main(String[] args) {
          Runnable runnable = () -> log.debug("aaa"); // 用来lamba表达式优化
          Thread t = new Thread(runnable);
          t.start();
      }
  }

方法三 :FutureTask配合Thread

复制代码
  @Slf4j
  public class Test {
      public static void main(String[] args) throws ExecutionException, InterruptedException {
          FutureTask<Integer> task = new FutureTask<>(new Callable<Integer>() {
              @Override
              public Integer call() throws Exception {
                  log.debug("running");
                  Thread.sleep(1000);
                  return 100;
              }
          });
          Thread t1 = new Thread(task,"t1");
          t1.start();
  ​
          // 等待task返回的结果
          log.debug("{}",task.get());
      }
  }

线程交替运行

复制代码
  
  @Slf4j
  public class Test {
      public static void main(String[] args){
          new Thread(() -> {
              while(true){
                  log.debug("running");
              }
          },"t1").start();
  ​
          new Thread(() -> {
              while(true){
                  log.debug("running");
              }
          },"t2").start();
  ​
      }
  }

线程运行原理

每次开启一个线程都会产生一个线程的栈给线程使用,实际上就是一开始分配的虚拟机栈。

  1. 每个栈都有多个栈帧

  2. 线程只能有一个活动栈帧

线程执行的过程

先分配栈给线程,线程调用main方法,在栈分配一个栈帧给main方法,栈帧保存锁记录、局部变量表、操作数栈、返回地址(返回到原来的栈帧方法的下一条指令)

线程上下文切换

导致上下文切换的条件

  • 时间片用完

  • 优先级

  • 垃圾回收

  • 自己调用sleep,wait等

线程的状态包括

  • 程序计数器,记录执行到什么位置

  • 虚拟机栈,包括所有的栈帧信息

常用方法

start

线程进入就绪状态,等待调度器调用。这里相当于是开启了一个新的线程

run

执行Runnable里面的方法。这里并没有开启线程,只是通过本线程执行代码

如果开启了两次start就会出现线程状态异常的问题IllegalThreadStateException

线程的两个状态

  • NEW

  • start之后就是Runnable等待被调度

sleep

线程睡眠,并且把状态改为Timed Waiting。被打断的时候会抛出异常InterruptedException。可以通过TimeUnit.SECONDS.sleep来规定睡眠时间的单位。睡眠可以使用在while循环自转的地方,如果长时间自转就会消耗CPU的使用时间,其它线程无法使用

yield

其实就是把线程状态从Running转变到Runnable暂时让出cpu(谦让),重新去竞争,具体实现看任务调度器,不一定礼让成功

interrupt

唤醒线程,如果线程处于睡眠状态那么就会抛出异常

复制代码
  
  @Slf4j
  public class Test {
      public static void main(String[] args) throws InterruptedException {
          Thread t = new Thread("t1"){
              @Override
              public void run() {
                  log.debug("enter sleep ...");
                  try {
                      Thread.sleep(2000);
                  } catch (InterruptedException e) {
                      log.debug("wake up ....");
                      e.printStackTrace();
                  }
              }
          };
          t.start();
          Thread.sleep(1000);
          t.interrupt();
      }
  }
复制代码
  
  ​
  @Slf4j
  public class Test {
  ​
  ​
      public static void main(String[] args) throws InterruptedException {
          Thread t = new Thread(() -> {
              log.debug("sleep。。。。");
              try {
                  Thread.sleep(5000);
              } catch (InterruptedException e) {
                  throw new RuntimeException(e);
              }
          },"t");
          t.start();
          Thread.sleep(1000);
          log.debug("interupt");
          t.interrupt();
          log.debug("打断标记 : {}",t.isInterrupted());
      }
  ​
  ​
  }

打断正常运行的线程

复制代码
  
  import lombok.extern.slf4j.Slf4j;
  ​
  ​
  @Slf4j
  public class Test {
  ​
  ​
      public static void main(String[] args) throws InterruptedException {
          Thread t1 = new Thread(() ->{
              while(true){
                  boolean interrupted = Thread.currentThread().isInterrupted();  // 打断标记
                  if(interrupted){
                      log.debug("被打断了, 退出循环");
                      break;
                  }
              }
          },"t1");
          t1.start();
  ​
          Thread.sleep(1000);
          log.debug("interupt");
          t1.interrupt();
      }
  ​
  ​
  }

setPriority

设置优先级是给调度器进行提示,先执行这个线程,但是仍然没有办法控制线程。

join

join实际上就是卡点,就是一定要等待调用join的线程完成之后才能够执行下面的代码

复制代码
  ​
  @Slf4j
  public class Test {
  ​
      static int r = 10;
  ​
      public static void main(String[] args) throws InterruptedException {
          test1();
      }
  ​
      public static void test1() throws InterruptedException {
          log.debug("开始");
          Thread t = new Thread(() -> {
              log.debug("开始");
              try {
                  Thread.sleep(1);
              } catch (InterruptedException e) {
                  throw new RuntimeException(e);
              }
              log.debug("结束");
              r = 10;
          },"t");
          t.start();
          t.join();   // 主线程等t线程结束
          log.debug("结果是 : {}",r);  // 打印10
      }
  }
相关推荐
jdksjw5 分钟前
同步与异步、阻塞与非阻塞、多线程、协程超详细讲解(Python并发编程从入门到精通)
开发语言·python
Zach_菠萝侠9 分钟前
【DeepSeek Harness 研究】进化方向4:安全加固 思考、设计与实现
开发语言·安全·deepseek
喜欢打篮球的普通人9 分钟前
LLVM Backend Lowering 从入门到实战:把 IR 变成机器码的完整链路
android·java·数据库
FL162386312939 分钟前
室内易燃物识别易燃评估室内易燃程度识别分割数据集labelme格式1015张85类别
java·服务器·前端
用户0595401744640 分钟前
把 AI 长期记忆去重测试从 20 分钟压到 40 秒,重复率从 18% 干到 1.5%
前端·css
SL-staff1 小时前
技术实践:HR如何用JVS-Logic可视化编排实现考勤数据同步(含节点配置与异常处理)
开发语言·python·低代码·钉钉·可视化编排·jvs-logic·hr技术
jufeng13071 小时前
【系列:TDengine 工业物联网实战:从零搭起可运行系统 · 第 8 篇】
java·spring boot·时序数据库·tdengine
kyriewen1 小时前
我把 AI 写的并发请求控制器手写了一遍——3 个语义我当时根本讲不清
前端·javascript·面试
SomeB1oody1 小时前
【RustyML入门】6.0. 数学工具
开发语言·后端·机器学习·rust·教程
程序员贺加贝1 小时前
轻制造SaaS的生产闭环建模-BOM工单领料报工质检与入库
java·设计模式·架构