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

目录

同步

两阶段终止模式

守护线程

线程状态

五种(操作系统角度)

[六种(Java API角度)](#六种(Java API角度))

烧水案例

共享模型之管程

临界区

竞态条件


同步

复制代码
  
  @Slf4j(topic = "c.TestJoin")
  public class TestJoin {
      static int r = 0;
      static int r1 = 0;
      static int r2 = 0;
  ​
      public static void main(String[] args) throws InterruptedException {
          test2();
      }
  ​
      public static void test3() throws InterruptedException {
          Thread t1 = new Thread(() -> {
              sleep(2);
              r1 = 10;
          });
  ​
          long start = System.currentTimeMillis();
          t1.start();
  ​
          // 线程执行结束会导致 join 结束
          log.debug("join begin");
          t1.join(3000);
          long end = System.currentTimeMillis();
          log.debug("r1: {} r2: {} cost: {}", r1, r2, end - start);
      }
  ​
      private static void test2() throws InterruptedException {
          Thread t1 = new Thread(() -> {
              sleep(1);
              r1 = 10;
          });
          Thread t2 = new Thread(() -> {
              sleep(2);
              r2 = 20;
          });
          t1.start();
          t2.start();
          long start = System.currentTimeMillis();
          log.debug("join begin");
  ​
          t1.join();
          log.debug("t1 join end");
          t2.join();
          log.debug("t2 join end");
          long end = System.currentTimeMillis();
          log.debug("r1: {} r2: {} cost: {}", r1, r2, end - start);
      }
  ​
      private static void test1() throws InterruptedException {
          log.debug("开始");
          Thread t1 = new Thread(() -> {
              log.debug("开始");
              sleep(1);
              log.debug("结束");
              r = 10;
          });
          t1.start();
          t1.join();
          log.debug("结果为:{}", r);
          log.debug("结束");
      }
  }

多线程的join只需要等待最长的那个线程就可以了,因为他们都是并行执行的。如果是t1先的话,那么就是t1在处理1秒的同时,t2也在处理一秒,然后t2执行join,那么还只剩下1s处理,那么t1和t2也只需要等待多1s就能够继续执行主线程的。

如果是t2先那么在处理2s的同时,t1已经先处理了1s并且进入了等待状态,等待t2处理完那么就可以执行主线程了。在t2的join end的同时,t1处理完,并且也会执行join end。

简单来说就是两个线程开启,如果下面两个都是join,那么实际上两个线程都会各自执行,互不干扰,直到最后一个线程执行完,那么才会执行join下面的代码。

test3案例,实际上就是限时等待,如果超过时间那么就不等了。如果没有超过时间,那么结束join还是以处理完线程的任务时间为主,而不是最大的等待时间

两阶段终止模式

复制代码
  
  ​
  @Slf4j
  public class Test {
      public static void main(String[] args) throws InterruptedException {
          TwoPhaseTermination tpt = new TwoPhaseTermination();
          tpt.start();
  ​
          Thread.sleep(3500);
          tpt.stop();
      }
  ​
  }
  ​
  @Slf4j
  class TwoPhaseTermination{
      private Thread monitor;
  ​
      // 启动监控线程
      public void start(){
          monitor = new Thread(() -> {
              while(true){
                  Thread thread = Thread.currentThread();
                  if(thread.isInterrupted()){
                      log.debug("料理后事");
                      break;
                  }
                  try {
                      Thread.sleep(1000);  // 情况一   在睡眠时被打断  打断标记是false
                      log.debug("监控记录");     // 情况二
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                      // 如果是睡眠中被打断 , 就重新设置打断标记
                      thread.interrupt();
                  }
              }
          });
          monitor.start();
      }
  ​
      // 停止监控线程
      public void stop() {
          monitor.interrupt();
      }
  }

打断park线程

复制代码
  
  @Slf4j
  public class Test {
      public static void main(String[] args) throws InterruptedException {
          Thread t1 = new Thread(() -> {
              log.debug("park...");
              LockSupport.park();
              log.debug("unpark");
              log.debug("打断状态: {}",Thread.currentThread().isInterrupted());
          },"t1");
          t1.start();
  ​
          Thread.sleep(1000);
          t1.interrupt();
      }
  ​
  }

守护线程

守护线程其实就是Daemon也就是在其他非守护线程运行完之后,无论守护线程是否还有任务需要执行都会强制停止。

  • 垃圾回收器是守护线程

  • tomcat的Acceptor和Poller

复制代码
  
  @Slf4j
  public class Test {
      public static void main(String[] args) throws InterruptedException {
          Thread t1 = new Thread(() -> {
              while(true){
                  if(Thread.currentThread().isInterrupted()){
                      break;
                  }
              }
              log.debug("结束");
          },"t1");
  ​
          t1.setDaemon(true);   // 设为守护线程
          t1.start();
          Thread.sleep(1000);
          log.debug("结束");
      }
  ​
  }
  ​

线程状态

五种(操作系统角度)

①初始:new线程的时候,只创建了,还没和操作系统关联

②可运行:执行了start

③运行:线程可以使用cpu的时候

④阻塞:不能被cpu调度器使用的时候

⑤终止:线程生命周期结束的时候

六种(Java API角度)

NEW:初始化

RUNNABLE:包括了运行、可运行和阻塞,通常表示正在运行

WAITING:没有时间限制

TIMED_WAITING:有时限的等待

BLOCKED:阻塞

TERMINATED:终止

烧水案例

复制代码
  
  @Slf4j
  public class Test {
      public static void main(String[] args) {
          Thread t1 = new Thread(() -> {
              log.debug("洗水壶");
              try {
                  Thread.sleep(1000);
              } catch (InterruptedException e) {
                  throw new RuntimeException(e);
              }
              log.debug("烧开水");
              try {
                  Thread.sleep(5000);
              } catch (InterruptedException e) {
                  throw new RuntimeException(e);
              }
          },"老王");
  ​
          Thread t2 = new Thread(() ->{
              log.debug("洗茶壶");
              try {
                  Thread.sleep(1000);
              } catch (InterruptedException e) {
                  throw new RuntimeException(e);
              }
              log.debug("洗茶杯");
              try {
                  Thread.sleep(1000);
              } catch (InterruptedException e) {
                  throw new RuntimeException(e);
              }
              log.debug("拿茶叶");
              try {
                  Thread.sleep(1000);
              } catch (InterruptedException e) {
                  throw new RuntimeException(e);
              }
              try {
                  t1.join();
              } catch (InterruptedException e) {
                  throw new RuntimeException(e);
              }
              log.debug("泡茶");
          }, "小王");
  ​
  ​
  ​
          t1.start();
          t2.start();
  ​
  ​
      }
  ​
  }

共享模型之管程

复制代码
  
  @Slf4j
  public class Test {
  ​
      static int counter = 0 ;
      public static void main(String[] args) throws InterruptedException {
          Thread t1 = new Thread(() ->{
              for (int i = 0; i < 5000; i++) {
                  counter ++ ;
              }
          });
  ​
          Thread t2= new Thread(() ->{
              for (int i = 0; i < 5000; i++) {
                  counter -- ;
              }
          });
  ​
  ​
          t1.start();
          t2.start();
          t1.join();
          t2.join();
          System.out.println(counter);    // 并不是输出0
  ​
      }
  ​
  }

临界区

实际上就是多个线程访问的代码里面有共享资源,那么这段代码就是临界区

竞态条件

如果在临界区中多线程执行发生执行指令序列不同导致结果无法预测的状况就是竞态条件

相关推荐
编程、小哥哥2 分钟前
设计模式之装饰器模式(SSO单点登录功能扩展,增加拦截用户访问方法范围场景)
java·设计模式·装饰器模式
TN_stark9329 分钟前
多进程/线程并发服务器
服务器·算法·php
液态不合群13 分钟前
Mysql篇-三大日志
数据库·mysql
喝醉酒的小白34 分钟前
数据库参数备份
数据库
汉克老师35 分钟前
GESP4级考试语法知识(贪心算法(四))
开发语言·c++·算法·贪心算法·图论·1024程序员节
小徍37 分钟前
MySQL 8.0特性-自增变量的持久化
数据库·mysql
糖豆大将军38 分钟前
Mysql个人八股总结
数据库·oracle
YRr YRr1 小时前
Ubuntu20.04 解决一段时间后键盘卡死的问题 ubuntu
linux·数据库·ubuntu
2401_857636391 小时前
实时数据流的革命:分布式数据库的挑战与实践
数据库·分布式
smj2302_796826521 小时前
用枚举算法解决LeetCode第3348题最小可整除数位乘积II
python·算法·leetcode