《Java并发编程之美》- 线程终止的方法

news2024/11/17 16:41:14

多线程并发编程之美

等待线程执行终止的 join 方法

执行的代码

public class MyThreadThree {
    public static void main(String[] args) throws InterruptedException {
        Thread thread_a=new Thread(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("child thread_a start run");
​
        });
        Thread thread_b=new Thread(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("child thread_b start run");
        });
​
        thread_a.start();
        thread_b.start();
​
        System.out.println("wait all child thread run over");
​
        thread_a.join();
        thread_b.join();
​
        System.out.println("all child thread run over");
    }
}

最终的执行结果:

wait all child thread run over all child thread run over thread_a start run thread_b start run

Process finished with exit code 0

主线程 main 在调用了子线程 thread_a 与 thread_b 的 join 方法之后,当前的主线程 main 处于阻塞的状态,直到线程 thread_a 与 thread_b 执行完毕后,才会继续执行当前的主线程 main 。

如果我注释掉线程 a 与线程 b 的两个方法,那么执行的结果是什么样的呢?没错,all child thread run over 这句主线程打印的话会在线程 a 与线程 b 输出之前执行(线程 a 与线程 b处于休眠状态)

public class MyThreadThree {
    public static void main(String[] args) throws InterruptedException {
        Thread thread_a=new Thread(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("thread_a start run");
​
        });
        Thread thread_b=new Thread(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("thread_b start run");
        });
​
        thread_a.start();
        thread_b.start();
​
        System.out.println("wait all child thread run over");
​
//        thread_a.join();
//        thread_b.join();
​
        System.out.println("all child thread run over");
    }
}

wait all child thread run over all child thread run over thread_a start run thread_b start run

Process finished with exit code 0

那么 join 方法的作用其实就变得很明显了,就是为了阻塞当前的线程,直到子线程的任务执行完毕。

我们可以将上面的第一部分的代码做一个小小的改动

public class MyThreadThree {
    public static void main(String[] args) throws InterruptedException {
        Thread thread_a=new Thread(()->{
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("thread_a start run");
​
        });
        Thread thread_b=new Thread(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("thread_b start run");
        });
​
        thread_a.start();
        thread_b.start();
​
        System.out.println("wait all child thread run over");
​
        thread_a.join();
        thread_b.join();
​
        System.out.println("all child thread run over");
    }
}

这样保证了线程打印的执行输出顺序为 main -> thread_a -> thread_b -> main

wait all child thread run over thread_b start run thread_a start run all child thread run over

Process finished with exit code 0

既然 join 可以阻塞当前的线程直到,调用 join 方法的线程执行完毕并返回后,才继续执行当前的线程,那么我们可以通过 join 来控制,线程 a 与线程 b 的执行是顺序。

我们对以上的代码做一稍微的修改即可。

public class MyThreadThree {
    public static void main(String[] args) throws InterruptedException {
        Thread thread_a=new Thread(()->{
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("thread_a start run");
​
        });
        Thread thread_b=new Thread(()->{
            try {
                //阻塞当前的线程 让其线程 a 先执行完毕
                thread_a.join();
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("thread_b start run");
        });
​
        thread_a.start();
        thread_b.start();
​
        System.out.println("wait all child thread run over");
​
        thread_a.join();
        thread_b.join();
​
        System.out.println("all child thread run over");
    }
}

执行的结果为:

wait all child thread run over thread_a start run thread_b start run all child thread run over

Process finished with exit code 0

可以看到线程 b 在执行到 thread_a.join() 的时候,线程 b 处于停滞阻塞的状态,等待线程 a 执行完毕,后线程的 b 才继续执行。

以上的两段程序执行所占用的时间也是不同的,第一段程序执行所占用的最大时间大致为 2 s,第二段程序执行完毕所占用的最大时间大致为 2 + 1 = 3 s。

【思考】

那么在多线程中提供这样的 join 阻塞当前调用线程的方法作用是什么呢?

在 《Java并发编程之美》-1.4小节[等待线程执行终止的 join 方法]中是这样解释的:

image-20221228101655039

好赖,就这样咯.

让线程睡眠的 sleep() 方法

执行下面的代码会发生什么?

  • sleep() 会让当前的线程进入睡眠的状态,该状态下的线程不参与 CPU 时间片的调度,但该线程拥有监视器资源,锁资源还是持有不让出的,当到达了指定的唤醒时间后,线程重新进入就绪状态,然后继续参与 CPU 时间片的调度.
public class ThreadFour {
​
    private static final Lock lock = new ReentrantLock();
​
    public static void main(String[] args) {
​
        Thread thread_a= new Thread(()->{
            lock.lock();
            try {
                System.out.println("thread_a is sleep");
                Thread.sleep(1000);
                System.out.println("thread_a is awaked");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
​
        });
        Thread thread_b=new Thread(()->{
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lock.lock();
            try {
                System.out.println("thread_b is sleep");
                Thread.sleep(1000);
                System.out.println("thread_b is awaked");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();
            }
        });
​
        thread_a.start();
        thread_b.start();
    }
}

thread_a is sleep thread_a is awaked thread_b is sleep thread_b is awaked

Process finished with exit code 0

如果在当前的线程处于睡眠的状态时,其他线程调用了当前线程的 interrupt() 方法,则会导致当前的线程抛出 InterruptedException 的中断异常.

CPU 让出执行的权的 yield 方法

public class YieldTest implements Runnable {
​
    YieldTest() {
        Thread thread = new Thread(this);
        thread.start();
    }
​
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            if (i % 5 == 0) {
                System.out.println(Thread.currentThread() + "yield CPU ... ");
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        System.out.println(Thread.currentThread() + "over");
    }
}
​
class test {
    public static void main(String[] args) {
        new YieldTest();
        new YieldTest();
        new YieldTest();
    }
}
public class YieldTest implements Runnable {
​
    YieldTest() {
        Thread thread = new Thread(this);
        thread.start();
    }
​
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            if (i % 5 == 0) {
                System.out.println(Thread.currentThread() + "yield CPU ... ");
                 Thread.yield();
            }
        }
        System.out.println(Thread.currentThread() + "over");
    }
}
​
class test {
    public static void main(String[] args) {
        new YieldTest();
        new YieldTest();
        new YieldTest();
    }
}

对比这两段代码可以发现什么?

第一段的代码在调用了 sleep(1) 方法后进入阻塞的状态,并且等待阻塞时间过期然后唤醒。(这种的情况出现的次数最多)

Thread[Thread-2,5,main]yield CPU … Thread[Thread-2,5,main]over Thread[Thread-0,5,main]yield CPU … Thread[Thread-1,5,main]yield CPU … Thread[Thread-0,5,main]over Thread[Thread-1,5,main]over

Process finished with exit code 0

第二段代码在调用 yield() 方法使当前线程让出 CPU 的执行时间片,线程调度器会从线程的队列中优先选出一个优先级别最高的线程进行执行,当前这个期间也有可能调用到刚刚让出 CPU 执行的时间片的线程。

所以第二段的代码片段在执行之后的结果是这样的:

*Thread[Thread-2,5,main]yield CPU … **Thread[Thread-1,5,main]yield CPU … **Thread[Thread-0,5,main]yield CPU … *Thread[Thread-1,5,main]over Thread[Thread-0,5,main]over Thread[Thread-2,5,main]over

Process finished with exit code 0

  • sleep()方法暂停当前线程后,会给其他线程执行机会,不区分其他线程的优先级;但yield()方法只会给优先级相同,或优先级更高的线程执行机会。(优先级区分)
  • sleep()方法会将线程转入阻塞状态,直到经过阻塞时间才会转入就绪状态;而yield()不会将线程转入阻塞状态,它只是强制当前线程进入就绪状态。因此完全有可能某个线程被yield()方法暂停之后,立即再次获得处理器资源被执行。(运行状态区分)
  • sleep()方法声明抛出了InterruptedException异常,所以调用sleep()方法时要么捕捉该异常,要么显式声明抛出该异常;而yield()方法则没有声明抛出任何异常。(抛出异常区分)

线程的中断

public class MyThreadFired {
    public static void main(String[] args) throws InterruptedException {
        Thread thread_a = new Thread(() -> {
            //获取当前的线程的中断标志并且重置
            while (!Thread.currentThread().interrupted()){
​
            }
            //获取当前线程的中断标志
            System.out.println("thread isInterrupted: " + Thread.currentThread().isInterrupted());
        });
        thread_a.start();
        //设置线程的中断标志
        thread_a.interrupt();
        Thread.sleep(1000);
        thread_a.join();
        System.out.println("main thread is over");
    }
}

执行结果:

thread isInterrupted: false main thread is over

Process finished with exit code 0

线程死锁

资源占用导致线程死锁

public class MyThreadLock {

    private static Object obj1=new Object();
    private static Object obj2=new Object();

    public static void main(String[] args) {
      Thread thread_a=  new Thread(()->{
            synchronized (obj1){
                System.out.println(Thread.currentThread() + "get obj1 Lock");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (obj2){
                    System.out.println(Thread.currentThread() + "get obj2 Lock");
                }
            }
        });
      Thread thread_b=new Thread(()->{
          synchronized (obj2){
              System.out.println(Thread.currentThread()+"get obj2 Lock");
              try {
                  Thread.sleep(1000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
              synchronized (obj1){
                  System.out.println(Thread.currentThread() + "get obj1 Lock");
              }
          }
      });

      thread_a.start();
      thread_b.start();
    }
}

Thread[Thread-0,5,main]get obj1 Lock Thread[Thread-1,5,main]get obj2 Lock

ThreadLocal 实现原理

先看两组代码

public class MyThreadLocalTest {

    static void print(String str) {
        //获取本地变量中的值
        System.out.println(str+":"+threadLocal.get());
        //清除本地变量中的值
//        threadLocal.remove();
    }

    //创建本地变量
    static ThreadLocal<String> threadLocal=new ThreadLocal<>();
    public static void main(String[] args) {
        Thread threadOne=new Thread(()->{
            //线程 One 获取本地线程变量中的值
            System.out.println("threadOne threadLocal vault "+threadLocal.get());
            //设置本地线程变量中的值
            threadLocal.set("卡卡罗特来咯!!!");
            threadLocal.set("卡卡罗特来咯!!!与他的儿子悟饭");
            //调用打印函数
            print("threadOne thread ");
            //再次打印本地线程变量中的值
            System.out.println("threadOne two threadLocal vault "+threadLocal.get());
        });

        Thread threadTwo=new Thread(()->{
            //获取本地线程变量中的值
            System.out.println("threadTwo threadLocal vault "+threadLocal.get());
            //设置本地线程变量值
            threadLocal.set("骄傲的贝吉塔!!!");
            print("threadTwo thread");

            System.out.println("threadTwo two threadLocal vault "+threadLocal.get());

        });


        threadOne.start();
        threadTwo.start();

    }
}

threadTwo threadLocal vault null threadOne threadLocal vault null *threadTwo thread:骄傲的贝吉塔!!! **threadTwo two threadLocal vault 骄傲的贝吉塔!!! *threadOne thread :卡卡罗特来咯!!!与他的儿子悟饭 threadOne two threadLocal vault 卡卡罗特来咯!!!与他的儿子悟饭

Process finished with exit code 0

public class MyThreadLocalTest {

    static void print(String str) {
        //获取本地变量中的值
        System.out.println(str+":"+threadLocal.get());
        //清除本地变量中的值
        threadLocal.remove();
    }

    //创建本地变量
    static ThreadLocal<String> threadLocal=new ThreadLocal<>();
    public static void main(String[] args) {
        
        Thread threadOne=new Thread(()->{
            //线程 One 获取本地线程变量中的值
            System.out.println("threadOne threadLocal vault "+threadLocal.get());
            //设置本地线程变量中的值
            threadLocal.set("卡卡罗特来咯!!!");
            threadLocal.set("卡卡罗特来咯!!!与他的儿子悟饭");
            //调用打印函数
            print("threadOne thread ");
            //再次打印本地线程变量中的值
            System.out.println("threadOne two threadLocal vault "+threadLocal.get());
        });

        Thread threadTwo=new Thread(()->{
            //获取本地线程变量中的值
            System.out.println("threadTwo threadLocal vault "+threadLocal.get());
            //设置本地线程变量值
            threadLocal.set("骄傲的贝吉塔!!!");
            print("threadTwo thread");

            System.out.println("threadTwo two threadLocal vault "+threadLocal.get());

        });

        threadOne.start();
        threadTwo.start();

    }
}

输出结果:

threadTwo threadLocal vault null *threadTwo thread:骄傲的贝吉塔!!! *threadTwo two threadLocal vault null threadOne threadLocal vault null threadOne thread :卡卡罗特来咯!!!与他的儿子悟饭 threadOne two threadLocal vault null

Process finished with exit code 0

代码分析:

两组代码都是调用了本地线程变量 threadLocal 并设置了不同的值。其区别在于第一段代码在调用 print 方法时执行了threadLocal.remove() 第二组代码中未执行,所以在第二组代码中,对于每一个线程而言,最后的第二次输出的本地线程变量中都是有其固定的值存在的。

问题:

  1. 设计 ThreadLocal 本地线程变量的目的与什么?
  2. 两个线程调用的是同一个 ThreadLocal 对象的引用都执行的 set 方法,其对于没一个线程而言是怎么保证其内部在调用 get 方法获取本地变量的时候不会发生混乱的呢?

首先第一个问题很好解决:

先了解一点,多线程环境下在操作同一个数据的时候最容易出现的问题是什么,对,就是在同一时间段内多个线程并发执行最终导致唯一的数据对象产生混乱,为了解决这一个问题,在多线程环境下引入了线程锁机制,保证一个数据对象在同一时间点只有一个线程去操作,保证数据的唯一性。但这样同样的也有一个问题的存在,锁机制简单的理解就是将之前的程序的执行由并行切换成了串行,这样如果并发量如果较高的情况下就会导致,程序的执行效率大幅度的降低。

其实对于这一问题 JDK 内部就提供一种解决方案,就是 ThreadLocal 线程本地变量。

通过字面意思就可以很好的理解,线程本地变量,就是对于每一个线程都有一个属于自己的存储在内存中的本地变量,也就是每一个线程内部的该变量都是独立的。

这里举个例子:

public class MyThreadLocalTestTwo {

    //构造一个公有变量

    private static String str = "";

    public static void main(String[] args) throws InterruptedException {
        //创建线程 A
        Thread thread_A = new Thread(() -> {
            if (str.equals("")) {
                //线程 A 对变量 str 进行修改
                str = "卡卡罗特";
                System.out.println(Thread.currentThread() + "===>" + str);
            }
        }, "thread_A");

        //创建线程 B
        Thread thread_B = new Thread(() -> {
            if (str.equals("")) {
                //线程 B 对变量 str 进行修改
                str = "特兰克斯";
                System.out.println(Thread.currentThread() + "===>" + str);
            }
        }, "thread_B");

        thread_A.start();
        thread_B.start();

    }
}

执行以上代码输出的结果是什么样呢?可能会出现以下结果:

Thread[thread_A,5,main]===>特兰克斯 Thread[thread_B,5,main]===>特兰克斯

Process finished with exit code 0

Thread[thread_B,5,main]===>特兰克斯

Process finished with exit code 0

Thread[thread_A,5,main]===>卡卡罗特

Process finished with exit code 0

这个与我们期望的理想输出的值存在差异,我们理想期望输出的为两个线程同时执行

线程 A 输出 卡卡罗特 ,线程 B 输出 特兰克斯

出现以上的结果就是应该共享变量在线程的并发情况下出现的混乱,我们可以使用 ThreadLocal 线程局部变量来处理

public class MyThreadLocalTestTwo {

    //构造一个公有变量

    private static String str = "";

    private static ThreadLocal<String> threadLocal = new ThreadLocal<>();

    public static void main(String[] args) throws InterruptedException {
        //创建线程 A
        Thread thread_A = new Thread(() -> {
            threadLocal.set(str);
            if (threadLocal.get().equals("")) {
                //线程 A 对变量 str 进行修改
                threadLocal.set("卡卡罗特");
                System.out.println(Thread.currentThread() + "===>" + threadLocal.get());
            }
        }, "thread_A");

        //创建线程 B
        Thread thread_B = new Thread(() -> {
            threadLocal.set(str);
            if (threadLocal.get().equals("")) {
                //线程 A 对变量 str 进行修改
                threadLocal.set("特兰克斯");
                System.out.println(Thread.currentThread() + "===>" + threadLocal.get());
            }
        }, "thread_B");

        thread_A.start();
        thread_B.start();

    }
}

Thread[thread_B,5,main]===>特兰克斯 Thread[thread_A,5,main]===>卡卡罗特

Process finished with exit code 0

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/349126.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

信息系统项目管理师真题精选(三)

1、以下关于我国现阶段电子政务建设的叙述中&#xff0c;不正确的是&#xff1a;&#xff08; &#xff09;。A.我国电子政务建设一直坚持统一规划&#xff0c;加强领导&#xff0c;需求主导&#xff0c;突出重点的原则B.我国电子政务建设一直坚持整合资源&#xff0c;拉动产业…

静态代理和动态代理的区别以及实现过程

前言 代理模式是一种设计模式&#xff0c;能够使得在不修改源目标的前提下&#xff0c;额外扩展源目标的功能。即通过访问源目标的代理类&#xff0c;再由代理类去访问源目标。这样一来&#xff0c;要扩展功能&#xff0c;就无需修改源目标的代码了。只需要在代理类上增加就可…

《真象还原》读书笔记——第五章 保护模式进阶,向内核迈进(特权级,更新)

5.4 特权级深入浅出 5.4.1 特权级哪点事 计算机 访问 可分为访问者和被访问者。 建立特权机制为了通过特权来检查合法性。 0、1、2、3级&#xff0c;数字越小&#xff0c;权力越大。 0特权级是系统内核特权级。 用户程序是3特权级&#xff0c;被设计为“有需求就找操作系统”…

QT+OpenGL光照

QTOpenGL光照 本篇完整工程见gitee:QtOpenGL 对应点的tag&#xff0c;由turbolove提供技术支持&#xff0c;您可以关注博主或者私信博主 颜色 现实生活中看到的物体的颜色并不是这个物体真正拥有的颜色&#xff0c;而是它所反射的颜色 太阳光能被看见的白光是多找演的的组合…

Linux部署项目

一、手动部署 1、终端直接部署&#xff08;前台运行&#xff09; &#xff08;1&#xff09;在IDEA中开发SpringBoot项目并打成jar包 &#xff08;2&#xff09;将jar包上传到Linux服务器 mkdir /usr/local/app #创建目录&#xff0c;将项目jar包放到此目录&#xff08;3&…

C++——哈希4|布隆过滤器

目录 布隆过滤器 完整代码 布隆过滤器应用 布隆过滤器的查找 布隆过滤器删除 布隆过滤器优点 布隆过滤器缺陷 布隆过滤器海量数据处理 布隆过滤器 位图只能映射整形&#xff0c;而对于字符串却无能为力。 把字符串用哈希算法转成整形&#xff0c;映射一个位置进行标…

Axure教程(一)——线框图与高保真原型图制作

前面我们学习了制作网页的技能&#xff0c;从这里开始我们来学习前端必备技能&#xff0c;就是用Axure来制作原型图&#xff0c;一方面我们能提前绘制出我们所需的页面&#xff0c;这在我们开发的时候能节省大量的时间&#xff0c;另一方面我们能通过给用户进行体验从而能够发现…

robotframework + selenium自动化测试常见的问题

1、 插入中文数据提示 FAIL UnicodeEncodeError: ‘latin-1’ codec can’t encode characters in position 92-107: ordinal not in range(25 DataBaseLibrary插入中文乱码的解决&#xff1a;修改D:\Python27\Lib\site-packages\DatabaseLibrary\connection_manager.py里的co…

极客大挑战 2021

题量很大&#xff0c;收获挺多&#xff0c;持续时间也长&#xff0c;据说结束之后会再持续一段时间&#xff0c;然后题目会开源。 WEB Dark 暗网签到&#xff0c;难以置信 Welcome2021 改个请求方法会提示你文件&#xff0c;再进去就好了 babysql 直接把请求包扔sqlmap里&…

什么是仓库管理?

仓库管理包括仓库日常运营所触及的准绳和流程。从较高的层次上讲&#xff0c;这包括接纳和组织仓库空间、布置劳动力、管理库存和完成订单。放大来看&#xff0c;你会发现有效的仓库管理触及到优化和集成这些过程中的每一个&#xff0c;以确保仓库操作的一切方面协同工作&#…

ElasticSearch之RestClient操作索引库和文档

前言&#xff1a;上文介绍了使用DSL语言操作索引库和文档&#xff0c;本篇文章将介绍使用Java中的RestClient来对索引库和文档进行操作。 希望能够加深自己的印象以及帮助到其他的小伙伴儿们&#x1f609;&#x1f609;。 如果文章有什么需要改进的地方还请大佬不吝赐教&#x…

linux系统编程1--文件编程read和write

write函数进行文件写入操作1.write函数原型&#xff1a;ssize_t write(int fd, const void *buf, size_t count);2.参数1&#xff1a;int fd&#xff0c;文件描述符即open函数的返回值&#xff1b;参数2&#xff1a;const void *buf&#xff0c;写入到fd文件内容的写入缓冲区&a…

10万字企业数字化(技术中台、数据中台、工业互联网平台建设方案

【版权声明】本资料来源网络&#xff0c;知识分享&#xff0c;仅供个人学习&#xff0c;请勿商用。【侵删致歉】如有侵权请联系小编&#xff0c;将在收到信息后第一时间删除&#xff01;完整资料关注公众号“智慧方案文库”&#xff0c;部分资料内容&#xff1a; 目录 1 概述 …

【nodejs-05】黑马nodejs学习笔记05-数据库基本操作02

文章目录4.在项目中操作MySQL4.1 在项目中操作数据库的步骤4.2 安装与配置 mysql 模块4.3 使用 mysql 模块操作 MySQL 数据库5.前后端的身份认证5.1 Web 开发模式5.2 身份认证5.3 Session 认证机制5.4 在 Express 中使用 Session 认证5.5 JWT 认证机制5.6 在 Express 中使用 JW…

用类比方式学习编程中函数递归(个人理解仅供参考)(内含汉诺塔问题的求解)

目录 1.前言 2.递归的数学模型 3.相关的c语法 4.将递归的数学模型写成编程语言 5.利用类比方法将实际问题的代码写成函数递归的形式 例1: 例2: 6.汉诺塔问题的求解 1.前言 本人在学习函数递归编程方法的过程中&#xff0c;发现用类比的方式学习递归法可帮助我们在各种编…

day14_类中成员之一:构造器

由来 我们发现我们new完对象时&#xff0c;所有成员变量都是默认值&#xff0c;如果我们需要赋别的值&#xff0c;需要挨个为它们再赋值&#xff0c;太麻烦了。我们能不能在new对象时&#xff0c;直接为当前对象的某个或所有成员变量直接赋值呢。可以&#xff0c;Java给我们提…

【算法】二分

作者&#xff1a;指针不指南吗 专栏&#xff1a;算法篇 &#x1f43e;或许会很慢&#xff0c;但是不可以停下来&#x1f43e; 文章目录1.二分思想2.二分模板3.二分应用1.二分思想 思想 单调的元素&#xff0c;一定可以二分&#xff1b;非单调不一定不能二分 每次把整个区间 [ …

【企业云端全栈开发实践-1】项目介绍及环境准备、Spring Boot快速上手

本节目录一、 项目内容介绍二、Maven介绍2.1 Maven作用2.2 Maven依赖2.3 本地仓库配置三、Spring Boot快速上手3.1 Spring Boot特点3.2 遇到的Bug&#xff1a;spring-boot-maven-plugin3.3 遇到的Bug2&#xff1a;找不到Getmapping四、开发环境热部署一、 项目内容介绍 本课程…

肿瘤HRR和HRD 简单记录

最近看到两个在肿瘤领域高频出现的词HRR和HRD&#xff0c; 遂简单记录下。 HRR和HRD的概念 当细胞受到外界不良环境的压力下往往会导致DNA的损伤&#xff0c;此时便会触发DNA 损伤反应 (DDR)&#xff0c;从而激活许多DNA修复通路。在这些DNA损伤中&#xff0c;DNA 双链断裂&a…

【云原生】centos7搭建安装k8s集群 v1.25版本详细教程实战

文章目录前言一. 实验环境二. k8s 的介绍三 . k8s的安装3.1 搭建实验环境3.1.1 硬件层面的要求3.1.2 软件层面环境配置3.2 docker的安装3.2.1 搭建docker3.2.2 部署 cri-dockerd3.3 部署k8s3.3.1 配置添加阿里云的yum源3.3.2 安装kubeadm kubelet kubectl3.3.3 k8s-master节点初…