山东大学软件学院项目实训-创新实训-基于大模型的旅游平台(十六)- 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
  ​
      }
  ​
  }

临界区

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

竞态条件

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

相关推荐
一颗花生米。12 分钟前
深入理解JavaScript 的原型继承
java·开发语言·javascript·原型模式
问道飞鱼13 分钟前
Java基础-单例模式的实现
java·开发语言·单例模式
hsling松子2 小时前
使用PaddleHub智能生成,献上浓情国庆福
人工智能·算法·机器学习·语言模型·paddlepaddle
dengqingrui1233 小时前
【树形DP】AT_dp_p Independent Set 题解
c++·学习·算法·深度优先·图论·dp
C++忠实粉丝3 小时前
前缀和(8)_矩阵区域和
数据结构·c++·线性代数·算法·矩阵
ZZZ_O^O3 小时前
二分查找算法——寻找旋转排序数组中的最小值&点名
数据结构·c++·学习·算法·二叉树
CV-King4 小时前
opencv实战项目(三十):使用傅里叶变换进行图像边缘检测
人工智能·opencv·算法·计算机视觉
ok!ko4 小时前
设计模式之原型模式(通俗易懂--代码辅助理解【Java版】)
java·设计模式·原型模式
代码雕刻家4 小时前
数据结构-3.9.栈在递归中的应用
c语言·数据结构·算法
雨中rain4 小时前
算法 | 位运算(哈希思想)
算法