Java多线程核心技术一-基础篇synchronzied同步方法

news2024/9/22 19:40:27

1 概述

        关键字synchronzied保障了原子性、可见性和有序性。

        非线程安全问题会在多个线程对同一个对象中的同一个实例变量进行并发访问时发生,产生的后果就是“脏读”,也就是读取到的数据其实是被更改过的。而线程安全是指获取的实例变量的值是经过同步处理的,不会出现脏读的现象。本篇将细化线程并发访问的内容,在细节上更多讲解并发时变量值的处理方法。

2 方法内的变量是线程安全的

        非线程安全问题存在时实例变量中,如果是方法内部私有变量,则不存在非线程安全问题,结果是线程安全的。

【示例1.1.1】演示方法内部声明一个变量时,是不存在“非线程安全”问题的。

public class HasSelfPrivateNum {
    public void addI(String username){
        try {
            int num = 0;
            if(username.equals("a")){
                num = 100;
                System.out.println("a set over");
                Thread.sleep(4000);
            }else{
                num = 200;
                System.out.println("b set over");
            }
            System.out.println(username + "num = " +num);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }

}

   

public class ThreadA extends Thread{
    private HasSelfPrivateNum numRef;

    public ThreadA(HasSelfPrivateNum numRef) {
        this.numRef = numRef;
    }
    @Override
    public void run(){
        numRef.addI("a");
    }
}

   

public class ThreadB extends Thread{
    private HasSelfPrivateNum refNef ;

    public ThreadB(HasSelfPrivateNum refNef) {
        this.refNef = refNef;
    }
    @Override
    public void run(){
        refNef.addI("b");
    }
}
public class RunDemo201 {
    public static void main(String[] args) {
        HasSelfPrivateNum hasSelfPrivateNum = new HasSelfPrivateNum();
        ThreadA a = new ThreadA(hasSelfPrivateNum);
        ThreadB b = new ThreadB(hasSelfPrivateNum);
        a.start();
        b.start();
    }
}

3 实例变量“非线程安全”问题及解决方案

        如果多个线程共同访问一个对象中的实例变量,则有可能出现非线程安全问题。线程访问的对象中如果有多个实例变量,则运行的结果有可能出现交叉的情况。把上面 HasSelfPrivateNum类中addI()方法的局部变量改为全局变量。在执行,num有可能被覆盖。

public class HasSelfPrivateNum {
    private int num = 0;
    public void addI(String username){
        try {

            if(username.equals("a")){
                num = 100;
                System.out.println("a set over");
                Thread.sleep(4000);
            }else{
                num = 200;
                System.out.println("b set over");
            }
            System.out.println(username + "num = " +num);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }

}

        这个实验是两个线程同时访问一个业务对象中的同一个没有同步的方法,如果两个线程同时操作业务对象中的实例变量,则有可能会出现非线程安全问题,根据前面的介绍,只需要在方法加上synchronized即可,更改后的代码:

public class HasSelfPrivateNum {
    private int num = 0;
    synchronized public void addI(String username){
        try {

            if(username.equals("a")){
                num = 100;
                System.out.println("a set over");
                Thread.sleep(4000);
            }else{
                num = 200;
                System.out.println("b set over");
            }
            System.out.println(username + "num = " +num);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }

}

 

4 同步synchronzied在字节码指令中的原理

        在方法上使用synchronzied关键字实现同步的原因是使用了flag标记ACC_SYNCHRONZIED,当调用方法时,调用质量会检查方法的ACC_SYNCHRONZIED访问标志是否设置,如果设置了,执行线程先持有同步锁,然后执行方法,最后在方法完成时释放锁。

【示例1.3.1】测试代码

public class TestSynchronzied {
    synchronized public  static void testMethod(){

    }

    public static void main(String[] args) throws InterruptedException{
        testMethod();
    }
}

使用javap命令把class文件转换成字节码指令,如下:

javap -c -v TestSynchronzied.class

生成这个class文件对应的字节码指令,指令的核心代码如下:

 public com.jay.current.demo213.TestSynchronzied();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       5     0  this   Lcom/jay/current/demo213/TestSynchronzied;

  public static synchronized void testMethod();
    descriptor: ()V
    flags: (0x0029) ACC_PUBLIC, ACC_STATIC, ACC_SYNCHRONIZED
    Code:
      stack=0, locals=0, args_size=0
         0: return
      LineNumberTable:
        line 6: 0

  public static void main(java.lang.String[]) throws java.lang.InterruptedException;
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=0, locals=1, args_size=1
         0: invokestatic  #7                  // Method testMethod:()V
         3: return
      LineNumberTable:
        line 9: 0
        line 10: 3
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0       4     0  args   [Ljava/lang/String;
    Exceptions:
      throws java.lang.InterruptedException

        在反编译的字节码指令中对public synchronzied void testMethod()方法使用了flag标记ACC_SYNCHRONZIED,说明此方法时同步的。

        如果使用synchronzied代码块,则使用monitorenter和monitorexit指令进行同步处理。测试代码如下:

public class TestSynchronzied_2 {
    public void testMethod(){
        synchronized (this){
            int age = 100;
        }
    }

    public static void main(String[] args) throws InterruptedException{
        TestSynchronzied_2 testSynchronzied2 = new TestSynchronzied_2();
        testSynchronzied2.testMethod();
    }
}

在CMD执行命令:

javap -c -v TestSynchronzied_2.class

生成的字节码指令如下:

 public void testMethod();
    descriptor: ()V
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=4, args_size=1
         0: aload_0
         1: dup
         2: astore_1
         3: monitorenter
         4: bipush        100
         6: istore_2
         7: aload_1
         8: monitorexit
         9: goto          17
        12: astore_3
        13: aload_1
        14: monitorexit
        15: aload_3
        16: athrow
        17: return
      Exception table:
         from    to  target type
             4     9    12   any
            12    15    12   any
      LineNumberTable:
        line 5: 0
        line 6: 4
        line 7: 7
        line 8: 17
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      18     0  this   Lcom/jay/current/demo213/TestSynchronzied_2;
      StackMapTable: number_of_entries = 2
        frame_type = 255 /* full_frame */
          offset_delta = 12
          locals = [ class com/jay/current/demo213/TestSynchronzied_2, class java/lang/Object ]
          stack = [ class java/lang/Throwable ]
        frame_type = 250 /* chop */
          offset_delta = 4

  public static void main(java.lang.String[]) throws java.lang.InterruptedException;
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: new           #7                  // class com/jay/current/demo213/TestSynchronzied_2
         3: dup
         4: invokespecial #9                  // Method "<init>":()V
         7: astore_1
         8: aload_1
         9: invokevirtual #10                 // Method testMethod:()V
        12: return
      LineNumberTable:
        line 11: 0
        line 12: 8
        line 13: 12
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      13     0  args   [Ljava/lang/String;
            8       5     1 testSynchronzied2   Lcom/jay/current/demo213/TestSynchronzied_2;
    Exceptions:
      throws java.lang.InterruptedException

        有代码可知,在字节码使用了monitorenter和monitorexit指令进行同步处理。

5 多个对象多个锁

        【示例1.4.1】

public class HasSelfPrivateNum {
    synchronized public void testMethod(){
        try {
            System.out.println(Thread.currentThread().getName() + " begin " + System.currentTimeMillis());
            Thread.sleep(3000);
            System.out.println(Thread.currentThread().getName() + " end " + System.currentTimeMillis());
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

         上面的代码有同步方法testMethod(),说明此方法在正常情况下应该被顺序调用。在创建两个线程类。

public class ThreadA extends Thread{
    private  HasSelfPrivateNum numRef;

    public ThreadA(HasSelfPrivateNum numRef) {
        this.numRef = numRef;
    }
    @Override
    public  void run(){
        numRef.testMethod();
    }
}
public class ThreadB extends Thread{
    private  HasSelfPrivateNum numRef;

    public ThreadB(HasSelfPrivateNum numRef) {
        this.numRef = numRef;
    }
    @Override
    public  void run(){
        numRef.testMethod();
    }
}

        最后创建main函数类

public class Run1 {
    public static void main(String[] args) {
        HasSelfPrivateNum num1 = new HasSelfPrivateNum();
        HasSelfPrivateNum num2 = new HasSelfPrivateNum();
        ThreadA a = new ThreadA(num1);
        a.start();
        ThreadB b = new ThreadB(num2);
        b.start();
    }
}

        运行结果:

        代码分析:首先创建了两个 HasSelfPrivateNum.java类的对象,即产生了两把锁。两个线程分别访问同一个类的两个不同示例的相同名称的同步方法(testMethod()),控制台输出了两个begin和end,且begin和end不是成对的输出,呈现了两个线程交叉输出的效果,说明两个线程以异步方式同时运行。

        本示例创建了两个业务对象,在系统中产生了两把锁,线程和业务对象属于一对一的关系,每个线程执行自己所属业务对象中的方法,不存在锁的争抢关系,所以运行结果是异步的。另外,在这种情况下synchronzied可以不需要,因为不会出现非线程安全的问题。

        只有多个线程执行统一个业务对象中的同步方法时,线程和业务对象属于多对一的关系,为了避免出现非线程安全问题,所以使用了synchronzied。

        总结:多个线程对共享的资源有写操作,则必须同步,如果只是读操作,则不需要同步。

6 synchronzied方法将对象作为锁

        为了证明上面说的将对象作为锁,开发以下代码:

public class MyObject {
    public  void methodA(){
        try{
            System.out.println("开始执行 methodA方法,线程名为:"+Thread.currentThread().getName());
            Thread.sleep(3000);
            System.out.println("end");
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

public class ThreadADemo215 extends Thread{
    private MyObject myObject;

    public ThreadADemo215(MyObject myObject) {
        this.myObject = myObject;
    }
    @Override
    public void  run(){
        myObject.methodA();
    }
}
public class ThreadBDemo215 extends Thread{
    private MyObject myObject;

    public ThreadBDemo215(MyObject myObject) {
        this.myObject = myObject;
    }
    @Override
    public void  run(){
        myObject.methodA();
    }
}
public class Run1 {
    public static void main(String[] args) {
        MyObject object = new MyObject();
        ThreadADemo215 a = new ThreadADemo215(object);
        a.setName("A");
        ThreadBDemo215 b = new ThreadBDemo215(object);
        b.setName("B");
        a.start();
        b.start();
    }
}

运行结果

        两个线程一同进入methodA方法,因为该方法没有同步。更改MyObject类,加上synchronzied关键字。

public class MyObject {
    synchronized public  void methodA(){
        try{
            System.out.println("开始执行 methodA方法,线程名为:"+Thread.currentThread().getName());
            Thread.sleep(3000);
            System.out.println("end");
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

 运行结果:

        通过上面的示例得到结论,调用关键字synchronzied声明的方法一定是排队运行。另外,需要记住“共享”这两个字,只有共享资源的写操作才需要同步,如果不是共享资源,是没有同步的必要的。 那其他方法被调用时会有什么效果呢?如何查看将对象作为锁的效果呢?重新修改MyObject.java类,新增一个没用synchronzied修改的方法methodB()

public class MyObject {
    synchronized public  void methodA(){
        try{
            System.out.println("开始执行 methodA方法,线程名为:"+Thread.currentThread().getName());
            Thread.sleep(3000);
            System.out.println("end");
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    public void methodB(){
        try{
            System.out.println("开始执行 methodB方法,线程名为:"+Thread.currentThread().getName());
            Thread.sleep(3000);
            System.out.println("end");
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

同时修改 ThreadBDemo215.java,run方法调用methodB()。运行结果:

        通过这个示例得知,虽然线程A先持有了object对象的锁,但线程B完全可以异步调用非synchronzied类型的方法。

        在把MyObject.java中的methodB方法加上synchronzied关键字,执行结果如下:

        两个线程访问同一个对象的两个同步方法。结论如下:

        1、A现成先持有object对象的锁,B现成可以以异步的方式调用object对象中的非synchronzied类型的方法。       

        2、A现成先持有object对象的锁,B现成如果在这时调用object对象中的synchronzied类型的方法,则需要等待A线程释放锁。

        3、在方法声明处添加sync并不是锁方法,而是锁当前类的对象。

        4、在java中,只有将对象作为锁,并没有锁方法这种说法。

        5、在Java中,锁就是对象,对象可以映射成锁,哪个线程拿到这把锁,哪个线程就可以执行这个对象中的synchronzied同步方法。

        6、如果在X对象中使用了synchronzied关键词声明非静态方法,则X对象就被当成锁。

7 脏读与解决

        在多个线程调用同一个方法时,为了避免数据出现交叉的情况,使用synchronzied关键字进行同步。虽然在赋值时进行了同步,但是在取值时有可能出现脏读。发生脏读的原因是在读取实例变量时,此值已经被其他线程更改过了。

【示例7.1】 

public class PublicVar {
    public String username = "A";
    public String password = "B";
    synchronized public void setValue(String username,String password){
        try{
            this.username = username;
            Thread.sleep(2000);
            this.password = password;
            System.out.println("执行setValue()方法,线程名是: "+Thread.currentThread().getName() + " username = " + username + ";password = " + password);
            
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
    public void getValue(){
        System.out.println("getValue()方法,线程名是: "+Thread.currentThread().getName() + " username = " + username + ";password = " + password);
    }
}
public class ThreadADemo216 extends Thread{
    private PublicVar publicVar;

    public ThreadADemo216(PublicVar publicVar) {
        this.publicVar = publicVar;
    }
    @Override
    public void run(){
        publicVar.setValue("B","BB");
    }
}
public class Test1 {
    public static void main(String[] args) {
        try {
            PublicVar publicVar = new PublicVar();
            ThreadADemo216 a = new ThreadADemo216(publicVar);
            a.start();
            Thread.sleep(2000);
            publicVar.getValue();
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

运行结果:

出现脏读是因为getValue方法并不是同步的,所以可以在任意时候进行调用,解决办法是加上synchronzied。

8 synchronzied锁重入

        关键词synchronzied拥有重入锁的功能,即在使用synchronzied时,当一个线程得到一个对象锁后,再次请求此对象锁时可以再次得到该对象的锁。这也证明在一个synchronzied方法/块的内部调用本类的其他synchronzied方法/this块时,是永远可以得到锁的。 

public class Service {
    synchronized public void service1(){
        System.out.println("service1");
        service2();
    }

    synchronized private void service2() {
        System.out.println("service2");
        service3();
    }

    synchronized private void service3() {
        System.out.println("service3");
    }
}
public class MyThread extends Thread{
    
    @Override
    public void run(){
        Service service = new Service();
        service.service1();
    }
}
public class Run1 {
    public static void main(String[] args) {
        MyThread t = new MyThread();
        t.start();
    }
}

        可重入锁是指自己可以再次获取自己的内部锁。例如,有1个线程获得了某个对象的锁,此时这个对象锁还没有释放,当其再次想要获取这个对象锁时还可以获取。如果是不可重入锁,方法service2和service3都不会被调用。

9 出现异常,锁自动释放

        当一个线程执行的代码出现异常时,其锁持有的锁会自动释放。

        【示例】

public class Service {
    synchronized public void testMethod(){
        if(Thread.currentThread().getName().equals("a")){
            System.out.println("线程名="+Thread.currentThread().getName()
            +"开始执行时间 = " + System.currentTimeMillis());
            int i = 1;
            while(i == 1){
                if(("" + Math.random()).substring(0,8).equals("0.123456")){
                    System.out.println("线程名="+Thread.currentThread().getName()
                            +"执行异常时间 = " + System.currentTimeMillis());
                    Integer.parseInt("a");
                }
            }
        }else{
            System.out.println("线程B运行时间 = " +System.currentTimeMillis());
        }
    }
    
}

        创建两个自定义线程。

public class ThreadA extends Thread{
    private Service service;

    public ThreadA(Service service) {
        this.service = service;
    }
    @Override
    public void run(){
        service.testMethod();
    }
}
public class ThreadB extends Thread{
    private Service service;

    public ThreadB(Service service) {
        this.service = service;
    }

    @Override
    public void run(){
        service.testMethod();
    }

}
public class Run1 {
    public static void main(String[] args) {
        try {
            Service service = new Service();
            ThreadA a = new ThreadA(service);
            a.setName("a");
            a.start();
            Thread.sleep(500);
            ThreadB b = new ThreadB(service);
            b.setName("b");
            b.start();
        }catch (InterruptedException e){
            e.printStackTrace();
        }


    }
}

        线程a出现异常并释放锁,线程b进入方法正常输出,说明出现异常时,锁被自动释放了。

        【注意】Thread.java中的suspend()和sleep()方法被调用后不会释放所。 

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

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

相关文章

年终好价节买什么好?这些数码好物闭眼入

大家是不是都没听说过好价节&#xff1f;直截了当地说&#xff0c;这其实就是原先的双十二购物狂欢节&#xff0c;只不过给它起了个新名字。不过&#xff0c;今年毕竟是首次改名&#xff0c;因此淘宝年终好价节的各种优惠&#xff0c;仍然是我们值得期待的&#xff01;作为年前…

2023.11.29 深度学习框架理解

2023.11.29 深度学习框架理解 对深度学习框架进行复习&#xff0c;选最简单的“三好学生”问题的四个变化&#xff0c;简要总结其具体思路。 深度学习一开始就是为分类问题研究的&#xff0c;因此其框架的设计都是基于分类的问题&#xff0c;虽然现在也已经演变为可以执行多种…

Java中的JMX的使用

文章目录 1. 定义和存在的意义2. 架构2.1 Instrumentation2.2 JMX Agent2.3 Remote Management 3. 启动和连接3.1 注册MBean3.2 有两个方式启动JMX Agent3.3 Remote Management(客户端) 4. MBeanServerConnection使用4.1 列出所有的MBean4.2 列出所有的Domain4.3 MBean计数4.4 …

Python (十六) 错误和异常

程序员的公众号&#xff1a;源1024&#xff0c;获取更多资料&#xff0c;无加密无套路&#xff01; 最近整理了一波电子书籍资料&#xff0c;包含《Effective Java中文版 第2版》《深入JAVA虚拟机》&#xff0c;《重构改善既有代码设计》&#xff0c;《MySQL高性能-第3版》&…

【Linux】基础IO--文件基础知识/文件操作/文件描述符

文章目录 一、文件相关基础知识二、文件操作1.C语言文件操作2.操作系统文件操作2.1 比特位传递选项2.2 文件相关系统调用2.3 文件操作接口的使用 三、文件描述符fd1.什么是文件描述符2.文件描述符的分配规则 一、文件相关基础知识 我们对文件有如下的认识&#xff1a; 1.文件 …

C 语言-数组

1. 数组 1.1 引入 需求&#xff1a;记录班级10个学员的成绩 需要定义10个变量存在的问题:变量名起名困难变量管理困难需求&#xff1a;记录班级1000个学员的成绩 1.2 概念 作用&#xff1a;容纳 数据类型相同 的多个数据的容器 。 特点&#xff1a; 长度不可变容纳 数据类型…

python实现two way ANOVA

文章目录 目的&#xff1a;用python实现two way ANOVA 双因素方差分析1. python代码实现1 加载python库2 加载数据3 统计样本重复次数&#xff0c;均值和方差&#xff0c;绘制箱线图4 查看people和group是否存在交互效应5 模型拟合与Two Way ANOVA&#xff1a;双因素方差分析6 …

ELFK集群部署(Filebeat+ELK) 本地收集nginx日志 远程收集多个日志

filebeat是一款轻量级的日志收集工具&#xff0c;可以在非JAVA环境下运行。 因此&#xff0c;filebeat常被用在非JAVAf的服务器上用于替代Logstash&#xff0c;收集日志信息。 实际上&#xff0c;Filebeat几乎可以起到与Logstash相同的作用&#xff0c; 可以将数据转发到Logst…

融资经理简历模板

这份简历内容&#xff0c;以综合柜员招聘需求为背景&#xff0c;我们制作了1份全面、专业且具有参考价值的简历案例&#xff0c;大家可以灵活借鉴。 融资经理简历在线编辑下载&#xff1a;百度幻主简历 求职意向 求职类型&#xff1a;全职 意向岗位&#xff1a;融资经理 …

Python Pyvis库:可视化复杂网络结构的利器

更多Python学习内容&#xff1a;ipengtao.com 大家好&#xff0c;我是涛哥&#xff0c;今天为大家分享 Python Pyvis库&#xff1a;可视化复杂网络结构的利器&#xff0c;全文4000字&#xff0c;阅读大约12钟。 在数据科学和网络分析领域&#xff0c;理解和可视化复杂网络结构是…

JeecgBoot低代码开发—Vue3版前端入门教程

JeecgBoot低代码开发—Vue3版前端入门教程 后端接口配置VUE3 必备知识1.vue3新特性a. https://v3.cn.vuejs.org/b.setup的用法c.ref 和 reactive 的用法d.新版 v-model 的用法e.script setup的用法 2.TypeScript基础 后端接口配置 如何修改后台项目路径 http://127.168.3.52:8…

Ubuntu systemd-analyze命令(系统启动性能分析工具:分析系统启动时间,找出可能导致启动缓慢的原因)

文章目录 Ubuntu systemd-analyze命令剖析目录简介systemd与systemd-analyze工作原理 安装和使用命令参数详解用例与示例显示启动时间&#xff08;systemd-analyze time&#xff09;列出启动过程中各个服务的启动时间&#xff08;systemd-analyze blame&#xff09;显示系统启动…

R语言单因素方差分析+差异显著字母法标注+逐行详细解释

R语言单因素方差分析 代码如下 df <- read.csv("data.csv",header TRUE,row.names 1) library(reshape2) df <- melt(df,idc()) names(df) <- c(trt, val) df aov1 <- aov(val~trt,datadf) summary(aov1)library(agricolae) data <- LSD.test(aov…

windows远程桌面登录,提示:“出现身份验证错误,要求的函数不受支持”

问题&#xff1a; windows登录远程桌面&#xff0c;提示&#xff1a;“出现身份验证错误&#xff0c;要求的函数不受支持”&#xff0c;如下图&#xff1a; 问题原因&#xff1a; windows系统更新&#xff0c;微软系统补丁的更新将 CredSSP 身份验证协议的默认设置进行了调…

【腾讯云云上实验室-向量数据库】个人对腾讯云向量数据库的体验心得

目录 前言Tencent Cloud VectorDB概念使用初体验腾讯云向量数据库的优势应用场景有哪些&#xff1f;未来展望番外篇&#xff1a;腾讯云向量数据库的设计核心结语 前言 还是那句话&#xff0c;不用多说想必大家都能猜到&#xff0c;现在技术圈最火的是什么&#xff1f;非人工智…

ZZULIOJ 2466: 楼上瞎说,楼下才是,Java

2466: 楼上瞎说&#xff0c;楼下才是 题目描述 《九章算术》的内容十分丰富&#xff0c;全书采用问题集的形式&#xff0c;收有246个与生产、生活实践有联系的应用问题&#xff0c;其中每道题有问&#xff08;题目&#xff09;、答&#xff08;答案&#xff09;、术&#xff…

【Vulnhub 靶场】【DriftingBlues: 9 (final)】【简单】【20210509】

1、环境介绍 靶场介绍&#xff1a;https://www.vulnhub.com/entry/driftingblues-9-final,695/ 靶场下载&#xff1a;https://download.vulnhub.com/driftingblues/driftingblues9.ova 靶场难度&#xff1a;简单 发布日期&#xff1a;2021年05月09日 文件大小&#xff1a;738 …

编程之外,生活的美好航程

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 仓库主页&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 欢迎点赞…

涵盖多种功能,龙讯旷腾Module第二期:电子结构及声子计算

Module是什么 在PWmat的基础功能上&#xff0c;我们针对用户的使用需求开发了一些顶层模块&#xff08;Module&#xff09;。这些Module中的一部分是与已有的优秀工具的接口&#xff0c;一部分是以PWmat的计算结果为基础得到实际需要的物理量&#xff0c;一部分则是为特定的计…

Jmeter接口测试:jmeter_HTTP Cookie管理器看这一篇文章就够了

HTTP Cookie管理器 HTTP Cookie管理器可以像浏览器一样自动存储和发送cookie&#xff0c;以这种自 动收集的方式收集到的cookie不会在cookie manager中进行展示&#xff0c;但是运行后&#xff0c; 可以通过 查看结果树&#xff08;监听器&#xff09;可以查看到cookie信息 除…