多线程与并发编程【线程对象锁、死锁及解决方案、线程并发协作、生产者与消费者模式】(四)-全面详解(学习总结---从入门到深化)

news2024/9/27 19:27:59

 

目录

使用Class作为线程对象锁

使用自定义对象作为线程对象锁

死锁及解决方案

线程并发协作(生产者/消费者模式)

 实现生产者与消费者模式


 

使用Class作为线程对象锁

 语法结构:

synchronized(XX.class){
      //同步代码
 }

synchronized public static void accessVal()
/**
* 定义销售员工类
*/
class Sale{
    private String name;
    public Sale(String name){
this.name = name;
   }
    /**
     * 领取奖金
     */
    synchronized  public static void money(){
            try {
              System.out.println(Thread.currentThread().getName() + " 被领导表扬");
                Thread.sleep(500);
              System.out.println(Thread.currentThread().getName() + " 拿钱");
                Thread.sleep(500);
              System.out.println(Thread.currentThread().getName() + " 对公司表示感谢");
                Thread.sleep(500);
              System.out.println(Thread.currentThread().getName() + " 开开心心的拿钱走人");
           } catch (InterruptedExceptione) {
                e.printStackTrace();
           }
       }
}
class Programmer{
    private String name;
    public Programmer(String name){
         this.name = name;
   }
    /**
     * 打开电脑
     */
    synchronized  public  void computer(){
            try {
              System.out.println(this.name + " 接通电源");
                Thread.sleep(500);
              System.out.println(this.name + " 按开机按键");
                Thread.sleep(500);
              System.out.println(this.name + " 系统启动中");
                Thread.sleep(500);
              System.out.println(this.name + " 系统启动成功");
           } catch (InterruptedExceptione) {
                e.printStackTrace();
           }
   }
    /**
     * 编码
     */
    synchronized public void coding(){
            try {
                    System.out.println(this.name + " 双击Idea");
                Thread.sleep(500);
              System.out.println(this.name + " Idea启动完毕");
                Thread.sleep(500);
              System.out.println(this.name + " 开开心心的写代码");
           } catch (InterruptedExceptione) {
                e.printStackTrace();
           }
       }
    /**
     * 去卫生间
     */
    public void wc(){
        synchronized ("suibian") {
            try {
              System.out.println(this.name + " 打开卫生间门");
                Thread.sleep(500);
              System.out.println(this.name + " 开始排泄");
                Thread.sleep(500);
              System.out.println(this.name + " 冲水");
                Thread.sleep(500);System.out.println(this.name + " 离开卫生间");
           } catch (InterruptedExceptione) {
                e.printStackTrace();
           }
       }
   }
    /**
     * 领取奖金
     */
    public void money(){
        synchronized (Programmer.class) {
            try {
              System.out.println(this.name + " 被领导表扬");
                Thread.sleep(500);
              System.out.println(this.name + " 拿钱");
                Thread.sleep(500);
              System.out.println(this.name + " 对公司表示感谢");
                Thread.sleep(500);
              System.out.println(this.name + " 开开心心的拿钱走人");
           } catch (InterruptedExceptione) {
                e.printStackTrace();
   }
       }
   }
}
/**
* 打开电脑的工作线程
*/
class Working1 extends Thread{
    private  Programmer p;
    public Working1(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.computer();
   }
}
/**
* 编写代码的工作线程
*/
class Working2 extends Thread{
    private  Programmer p;
    public Working2(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.coding();
   }
}
/**
* 去卫生间的线程
*/
class WC extends Thread{
    private  Programmer p;
    public WC(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.wc();
   }
}
/**
* 程序员领取奖金
*/
class ProgrammerMoney extends Thread{
    private  Programmer p;
    public ProgrammerMoney(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.money();
   }
}
/**
* 销售部门领取奖金
*/
class SaleMoney extends  Thread{
    private  Sale p;
    public SaleMoneyThread(Sale p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.money();
   }
}
public class TestSyncThread {
    public static void main(String[] args)
{
       /* Programmer p = new Programmer("张三");
        Programmer p1 = new Programmer("李四");
        new ProgrammerMoney(p).start();
        new ProgrammerMoney(p1).start();*/
        
        Sale s = new Sale("张晓丽");
        Sale s1 = new Sale("王晓红");
        new SaleMoney(s).start();
        new SaleMoney(s1).start();
   }
}

使用自定义对象作为线程对象锁

语法结构:

synchronized(自定义对象){
      //同步代码
}
/**
* 定义销售员工类
*/
class Sale{
    private String name;
    public Sale(String name){
        this.name = name;
   }
    /**
     * 领取奖金
     */
    synchronized  public static void money(){
            try {
                System.out.println(Thread.currentThread(). getName() + " 被领导表扬");
                Thread.sleep(500);
              System.out.println(Thread.currentThread().getName() + " 拿钱");
                Thread.sleep(500);
              System.out.println(Thread.currentThread().getName() + " 对公司表示感谢");
                Thread.sleep(500);
              System.out.println(Thread.currentThread().getName() + " 开开心心的拿钱走人");
           } catch (InterruptedExceptione) {
                e.printStackTrace();
           }
       }
}
class Programmer{
    private String name;
    public Programmer(String name){
        this.name = name;
   }
    /**
     * 打开电脑
     */
    synchronized  public  void computer(){
            try {
                   System.out.println(this.name + " 接通电源");
                   Thread.sleep(500);
                   System.out.println(this.name + " 按开机按键");
                   Thread.sleep(500);
                   System.out.println(this.name + " 系统启动中");
                Thread.sleep(500);
              System.out.println(this.name + " 系统启动成功");
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
   }
    /**
     * 编码
     */
    synchronized public void coding(){
            try {
              System.out.println(this.name + " 双击Idea");
                Thread.sleep(500);
              System.out.println(this.name + " Idea启动完毕");
                Thread.sleep(500);
              System.out.println(this.name + " 开开心心的写代码");
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
       }
    /**
     * 去卫生间
     */
    public void wc(){
        synchronized ("suibian") {
            try {
               System.out.println(this.name + " 打开卫生间门");
                Thread.sleep(500);
               System.out.println(this.name + " 开始排泄");
                Thread.sleep(500);
               System.out.println(this.name + " 冲水");
                Thread.sleep(500);
               System.out.println(this.name + " 离开卫生间");
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
       }
 }
    /**
     * 领取奖金
     */
    public void money(){
        synchronized (Programmer.class) {
            try {
                 System.out.println(this.name + " 被领导表扬");
                Thread.sleep(500);
                 System.out.println(this.name + " 拿钱");
                Thread.sleep(500);
                System.out.println(this.name + " 对公司表示感谢");
                Thread.sleep(500);
                System.out.println(this.name + " 开开心心的拿钱走人");
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
       }
   }
}
class Manager{
    private String name;
    public Manager(String name){
        this.name = name;
}
    public String getName(){
        return this.name;
   }
    /**
     * 敬酒
     */
    public void cheers(String mName,String eName){
            try {
                System.out.println(mName + " 来到 " + eName + " 面前");
                Thread.sleep(500);
                System.out.println(eName + " 拿起酒杯");
                Thread.sleep(500);
                System.out.println(mName + " 和 " + eName + " 干杯");
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
   }
}
/**
* 打开电脑的工作线程
*/
class Working1 extends Thread{
    private  Programmer p;
    public Working1(Programmer p){
        this.p = p;
   }
  @Override
    public void run() {
        this.p.computer();
   }
}
/**
* 编写代码的工作线程
*/
class Working2 extends Thread{
    private  Programmer p;
    public Working2(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.coding();
   }
}
/**
* 去卫生间的线程
*/
class WC extends Thread{
    private  Programmer p;
    public WC(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.wc();
   }
}
/**
* 程序员领取奖金
*/
class ProgrammerMoney extends Thread{
    private  Programmer p;
    public ProgrammerMoney(Programmer p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.money();
   }
}
/**
* 销售部门领取奖金
*/
class SaleMoneyThread extends  Thread{
    private  Sale p;
    public SaleMoneyThread(Sale p){
        this.p = p;
   }
    @Override
    public void run() {
        this.p.money();
   }
}
/**
* 敬酒线程类
*/
class CheersThread extends Thread{
    private Manager manager;
    private String name;
    public CheersThread(String name,Manager manager){
        this.name = name;
        this.manager = manager;
   }
    @Override
    public void run() {
        synchronized (this.manager) {
          
this.manager.cheers(this.manager.getName() , name);
       }
   }
}
public class TestSyncThread {
    public static void main(String[] args)
{
        Manager manager = new Manager("张三丰");
        new CheersThread("张三",manager).start();
        new CheersThread("李四",manager).start();
   }
}

死锁及解决方案

死锁的概念

 “死锁”指的是: 多个线程各自占有一些共享资源,并且互相等待其他线程占有的资 源才能进行,而导致两个或者多个线程都在等待对方释放资源,都 停止执行的情形。

某一个同步块需要同时拥有“两个以上对象的锁”时,就可能会发 生“死锁”的问题。比如,“化妆线程”需要同时拥有“镜子对象”、 “口红对象”才能运行同步块。那么,实际运行时,“小丫的化妆 线程”拥有了“镜子对象”,“大丫的化妆线程”拥有了“口红对象”, 都在互相等待对方释放资源,才能化妆。这样,两个线程就形 成了互相等待,无法继续运行的“死锁状态”。

 死锁案例演示

/**
* 口红类
*/
   class Lipstick{
     }
/**
* 镜子类
*/
   class Mirror{
   }
/**
* 化妆线程类
*/
class Makeup extends Thread{
    private int flag; //flag=0:拿着口红。 flag!=0:拿着镜子
    private String girlName;
    static Lipstick lipstick = new Lipstick();
    static Mirror mirror = new Mirror();
    public Makeup(int flag,String girlName){
        this.flag  = flag;
        this.girlName = girlName;
   }
    @Override
    public void run() {
        this.doMakeup();
   }
    /**
     * 开始化妆
     */
    public void doMakeup(){
        if(flag == 0){
            synchronized (lipstick){
              System.out.println(this.girlName+" 拿着口红");
                try {
                    Thread.sleep(1000);
               } catch (InterruptedException e) {
                    e.printStackTrace();
               }
                synchronized (mirror){
               System.out.println(this.girlName+" 拿着镜子");
               }
           }
       }else{
            synchronized (mirror){
              System.out.println(this.girlName+" 拿着镜子");
                try {
                    Thread.sleep(2000);
               } catch(InterruptedException e) {
                    e.printStackTrace();
               }
                synchronized (lipstick){
                  System.out.println(this.girlName+" 拿着口红");
               }
           }
       }
   }
}
public class DeadLockThread {
    public static void main(String[] args) {
        new Makeup(0,"大丫").start();
        new Makeup(1,"小丫").start();
   }
}

死锁问题的解决

死锁是由于 “同步块需要同时持有多个对象锁造成”的,要解决这个 问题,思路很简单,就是:同一个代码块,不要同时持有两个对象 锁。

/**
* 口红类
*/
    class Lipstick{
     }
/**
* 镜子类
*/
    class Mirror{
    }
/**
* 化妆线程类
*/
class Makeup extends Thread{
    private int flag; //flag=0:拿着口红。 flag!=0:拿着镜子
    private String girlName;
    static Lipstick lipstick = new Lipstick();
    static Mirror mirror = new Mirror();
    public void setFlag(int flag) {
        this.flag = flag;
      }
    public void setGirlName(String girlName)
      {
        this.girlName = girlName;
      }
    @Override
    public void run() {
        this.doMakeup();
     }
    /**
     * 开始化妆
     */
    public void doMakeup(){
        if(flag == 0){
            synchronized (lipstick){
              System.out.println(this.girlName+" 拿着口红");
                try {
                    Thread.sleep(1000);
               } catch(InterruptedException e) {
                    e.printStackTrace();
               }
           }
            synchronized (mirror){
             System.out.println(this.girlName+" 拿着镜子");
           }
       }else{
            synchronized (mirror){
              System.out.println(this.girlName+" 拿着镜子");
                try {
                    Thread.sleep(2000);
               } catch(InterruptedException e) {
                    e.printStackTrace();
               }
           }
            synchronized (lipstick){
              System.out.println(this.girlName+" 拿着口红");
           }
       }
   }
}
public class DeadLockThread {
    public static void main(String[] args) {
        Makeup makeup = new Makeup();
        makeup.setFlag(0);
        makeup.setGirlName("大丫");
        Makeup makeup1 = new Makeup();
        makeup1.setFlag(1);
        makeup1.setGirlName("小丫");
        makeup.start();
        makeup1.start();
   }
}

死锁问题的解决

死锁是由于 “同步块需要同时持有多个对象锁造成”的,要解决这个 问题,思路很简单,就是:同一个代码块,不要同时持有两个对象 锁。

/**
* 口红类
*/
     class Lipstick{
     }
/**
* 镜子类
*/
    class Mirror{
    }
/**
* 化妆线程类
*/
class Makeup extends Thread{
    private int flag; //flag = 0 :拿着口红,flag != 0 :拿着镜子
  private String girlName;
    static Lipstick lipstick = new Lipstick();
    static Mirror mirror = new Mirror();
    public Makeup(int flag,String girlName){
        this.flag = flag;
        this.girlName = girlName;
   }
    @Override
    public void run() {
        this.doMakeup();
   }
    /**
     * 开始化妆
     */
    public void doMakeup(){
        if(this.flag == 0){
            synchronized (lipstick){
               System.out.println(this.girlName+" 拿着口红");
                try {
                    Thread.sleep(1000);
               } catch(InterruptedException e) {
                    e.printStackTrace();
               }
           }
 synchronized (mirror){
              System.out.println(this.girlName+" 拿着镜子");
           }
       }else{
            synchronized (mirror){
              System.out.println(this.girlName+" 拿着镜子");
                try {
                    Thread.sleep(2000);
               } catch(InterruptedException e) {
                    e.printStackTrace();
               }
           }
            synchronized (lipstick){
              System.out.println(this.girlName+" 拿着口红");
           }
       }
   }
}
public class DeadLockThread {
    public static void main(String[] args) {
  new Makeup(0,"小丫").start();
        new Makeup(1,"大丫").start();
   }
}

线程并发协作(生产者/消费者模式)

 多线程环境下,我们经常需要多个线程的并发和协作。这个时候, 就需要了解一个重要的多线程并发协作模型“生产者/消费者模式”。

 角色介绍

   什么是生产者?

      生产者指的是负责生产数据的模块(这里模块可能是:方法、对 象、线程、进程)。

  什么是消费者?

    消费者指的是负责处理数据的模块(这里模块可能是:方法、对 象、线程、进程)。

  什么是缓冲区?

    消费者不能直接使用生产者的数据,它们之间有个“缓冲区”。生 产者将生产好的数据放入“缓冲区”,消费者从“缓冲区”拿要处理 的数据。

 缓冲区是实现并发的核心,缓冲区的设置有两个好处:

1 实现线程的并发协作

有了缓冲区以后,生产者线程只需要往缓冲区里面放置数据,而 不需要管消费者消费的情况;同样,消费者只需要从缓冲区拿数 据处理即可,也不需要管生产者生产的情况。 这样,就从逻辑 上实现了“生产者线程”和“消费者线程”的分离,解除了生产者与 消费者之间的耦合。

2 解决忙闲不均,提高效率

生产者生产数据慢时,缓冲区仍有数据,不影响消费者消费;消 费者处理数据慢时,生产者仍然可以继续往缓冲区里面放置数据 。

 实现生产者与消费者模式

创建缓冲区

/**
* 定义馒头类
*/
class ManTou{
    private int id;
    public ManTou(int id){
        this.id = id;
   }
  public int getId(){
        return this.id;
   }
}
/**
* 定义缓冲区类
*/
class SyncStack{
    //定义存放馒头的盒子
    private ManTou[] mt = new ManTou[10];
    //定义操作盒子的索引
    private int index;
    /**
     * 放馒头
     */
    public synchronized void push(ManTou manTou){
        //判断盒子是否已满
        while(this.index == this.mt.length){
            try {
                /**
                 * 语法:wait(),该方法必须要在 synchronized块中调用。
                 * wait执行后,线程会将持有的对象锁释放,并进入阻塞状态,
                 * 其他需要该对象锁的线程就可以继续运行了。
                 */
                this.wait();
               } catch (InterruptedException e){
                e.printStackTrace();
           }
       }
        //唤醒取馒头的线程
        /**
         * 语法:该方法必须要在synchronized块中调用。
         * 该方法会唤醒处于等待状态队列中的一个线程。
         */
        this.notify();
        this.mt[this.index] = manTou;
        this.index++;
   }
    /**
     * 取馒头
     */
    public synchronized ManTou pop(){
        while(this.index == 0){
            try {
                /**
                 * 语法:wait(),该方法必须要在synchronized块中调用。
                 * wait执行后,线程会将持有的对象锁释放,并进入阻塞状态,
                 * 其他需要该对象锁的线程就可以继续运行了。
                 */
                this.wait();
           } catch (InterruptedException e)
           {
                e.printStackTrace();
           }
       }
        this.notify();
        this.index--;
        return this.mt[this.index];
   }
}
public class TestProduceThread {
    public static void main(String[] args) {
      
   }
}

创建生产者消费者线程

/**
* 定义馒头类
*/
class ManTou{
    private int id;
    public ManTou(int id){
        this.id = id;
   }
    public int getId(){
        return this.id;
   }
}
/**
* 定义缓冲区类
*/
class SyncStack{
    //定义存放馒头的盒子
    private ManTou[] mt = new ManTou[10];
    //定义操作盒子的索引
    private int index;
    /**
     * 放馒头
     */
    public synchronized void push(ManTou manTou){
        //判断盒子是否已满
        while(this.index == this.mt.length)
          {
            try {
                /**
                 * 语法:wait(),该方法必须要在 synchronized块中调用。
                 * wait执行后,线程会将持有的对象锁释放,并进入阻塞状态,
                 * 其他需要该对象锁的线程就可以继续运行了。
                 */
                this.wait();
           } catch (InterruptedException e) {
                e.printStackTrace();
          }
       }
        //唤醒取馒头的线程
        /**
         * 语法:该方法必须要在synchronized块中调用。
         * 该方法会唤醒处于等待状态队列中的一个线程。
         */
        this.notify();
        this.mt[this.index] = manTou;
        this.index++;
   }
    /**
     * 取馒头
     */
    public synchronized ManTou pop(){
        while(this.index == 0){
            try {
                /**
                 * 语法:wait(),该方法必须要在synchronized块中调用。
                 * wait执行后,线程会将持有的对象锁释放,并进入阻塞状态,
                 * 其他需要该对象锁的线程就可以继续运行了。
                 */
                this.wait();
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
       }
        this.notify();
        this.index--;
        return this.mt[this.index];
   }
}
/**
* 定义生产者线程类
*/
class ShengChan extends Thread{
    private SyncStack ss;
    public ShengChan(SyncStack ss){
        this.ss = ss;
   }
    @Override
    public void run() {
       for(int i=0;i<10;i++){
           System.out.println("生产馒头:"+i);
           ManTou manTou = new ManTou(i);
           this.ss.push(manTou);
       }
   }
}
/**
* 定义消费者线程类
*/
class XiaoFei extends Thread{
    private SyncStack ss;
    public XiaoFei(SyncStack ss){
        this.ss = ss;
   }
    @Override
    public void run() {
        for(int i=0;i<10;i++){
           ManTou manTou = this.ss.pop();
            System.out.println("消费馒头:"+i);
       }
   }
}
public class ProduceThread {
    public static void main(String[] args)
{
        SyncStack ss = new SyncStack();
        new ShengChan(ss).start();
        new XiaoFei(ss).start();
   }
}

线程并发协作总结

线程并发协作(也叫线程通信)

   生产者消费者模式:

1 生产者和消费者共享同一个资源,并且生产者和消费者之间相互 依赖,互为条件。

2 对于生产者,没有生产产品之前,消费者要进入等待状态。而生 产了产品之后,又需要马上通知消费者消费。

3 对于消费者,在消费之后,要通知生产者已经消费结束,需要继 续生产新产品以供消费。4 在生产者消费者问题中,仅有synchronized是不够的。 synchronized可阻止并发更新同一个共享资源,实现了同步但 是synchronized不能用来实现不同线程之间的消息传递(通 信)。

5 那线程是通过哪些方法来进行消息传递(通信)的呢?见如下总 结:

 6 以上方法均是java.lang.Object类的方法;

都只能在同步方法或者同步代码块中使用,否则会抛出异常。

OldLu建议 在实际开发中,尤其是“架构设计”中,会大量使用这个模式。 对于初学者了解即可,如果晋升到中高级开发人员,这就是必 须掌握的内容。

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

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

相关文章

【大语言模型】LLM应用程序的新兴体系结构

LLM应用程序的新兴体系结构 LLM应用栈设计模式&#xff1a;In-context learningData Preprocessing/EmbeddingPrompt Construction/RetrievalPrompt Execution/Inference What about agents?展望参考资料 大型语言模型是构建软件的强大新基元。但由于它们非常新颖且与常规计算…

css写法、颜色显示方式

一、什么是css 二、css的几种写法 1、行内样式 css写在标签的style属性上&#xff0c;优先级非常高&#xff0c;但是有多个标签具有相同样式代码重复高 2、页面样式 此时写在head&#xff08;不可见&#xff09;中&#xff0c;用style标签 3、外联样式 css样式也可以导入 一…

C++primer(第五版)第十六章(模板与泛型编程)

16.1定义模板 关于模板,第一个要提的点就是,这个字念mu模板而不是mo(一开始打字就发现拼音错了,突然觉得自己要会小学深造一下). 模板就是将一个特定场合使用的东西变成可以在多个场合使用的东西. 16.1.1函数模板 template<typename T> bool bijiao(T &a,T &…

了解 IPNS:我们可以使用 4EVERLAND IPNS Manager 做什么?

关键词&#xff1a;4EVERLAND、IPNS、4EVERLAND IPNS 管理器、去中心化内容 IPNS 是星际名称系统的缩写&#xff0c;是一个允许我们在 IPFS&#xff08;星际文件系统&#xff09;内创建可变指针以及名称和地址内容的系统。IPFS 使用内容标识符 (CID) 作为唯一文件标识符&#…

Photoshop制作Alphas(没有显卡好痛苦,两个MAYA交替弄)

做个选区&#xff0c;选白色 擦除背景 在把背景填充上白色

【PyGIS】GDAL及Rasterio多线程转换NC格式文件为TIFF

汇总 【GIS】使用cdsapi下载ERA5和ERA5_land逐小时数据 NC格式介绍 说明 NC文件读取使用netCDF4,NC文件转换为TIF使用rasterio或者GDAL。 一些细节: 格点数据转换为TIFF文件时候,计算六参数时候,应该要考虑,格点数据存储的坐标属于栅格中心点的位置,转换为TIFF时候,…

Java----使用eureka进行注册连接(微服务简单实现)

当采用微服务架构时&#xff0c;各个业务流程被逐一分解&#xff0c;虽说是分解&#xff0c;但还是要进行连接的&#xff0c;最简单的就是使用http请求&#xff0c;将他们联系起来&#xff0c;通过给容器注入restTemplate&#xff0c;然后使用内置的方法进行请求&#xff0c;但…

基于Javaweb实现ATM机系统开发实战(四)用户修改删除功能实现

我们点一下修改&#xff0c;发现页面进行了跳转&#xff0c;跳转到了/toUpdate&#xff0c;并传递了用户的卡号。 我们可以先查看一下用户列表展示界面的前端代码&#xff1a;userlist.jsp&#xff0c;可以看到前端代码中做了跳转的动作&#xff0c;我们需要在后端中完成相应的…

VectorCAST单元测试参数配置

一、打开 VectorCAST 通常情况下&#xff0c;技术人员会配置一个脚本文件&#xff08;.bat、.cmd&#xff09;&#xff0c;用户可以通过这个脚本文件来启动 VectorCAST。使用脚本文件启动 VectorCAST&#xff0c;可以在启动时设置好编译器相关的环境变量&#xff0c;方便 Vecto…

企业毛利高,进项抵扣少,增值税高,怎么办?

企业毛利高&#xff0c;进项抵扣少&#xff0c;增值税高&#xff0c;怎么办&#xff1f; 《税筹顾问》专注于园区招商、企业税务筹划&#xff0c;合理合规助力企业节税&#xff01; 金税四期的出现&#xff0c;让很多企业都陷入了税负重的不利局面。当然了在此环境之下&#x…

回溯法总结

文章目录 回溯法如何理解回溯法 回溯算法模板框架如下&#xff1a;树枝去重树层去重回溯法去重什么时候去重&#xff1f;树层去重数组used[i-1]&#xff1a;回溯函数的参数startIndex&#xff1a;回溯函数的参数用Set的对象uset&#xff1a;局部变量例题 其它细节对于组合问题&…

测试开发知识图谱

目录 前言&#xff1a; 1 测试方法与理论 2 Shell脚本相关 3 数据库相关 4 git 代码管理 5 Python 编程语言与测试框架 6 Web 自动化测试 7 移动端 app 自动化测试 8 常用开源测试平台 9 客户端专项测试 10 服务端接口测试 11 服务端接口自动化测试 12 服务端性能…

国产CAN收发器XL1050可替代NXP的TJA1050T,性能参数基本一致

CAN收发器是CAN控制器和物理总线之间的接口&#xff0c;在工控等需要CAN通信的应用场合是必要的&#xff0c;工程师通常采用NXP、TI等品牌的&#xff0c;TJA1050T是常见型号之一。XL1050是信路达一款CAN收发器&#xff0c;本文讨论信路达的XL1050 替代NXP的TJA1050T的可行性。 …

前后端分离,前端代理设置

1. 没有vue.config.js的配置方法 1.1 在config目录下的index.js里面加入如下所示代码 proxyTable: {"/api": { // 不能写成^/apitarget: "http://localhost:50000", // 只写域名即可ws: true,changeOrigin: true, // 允许跨域pathRewrite: { // 重写&…

leetcode:除自身以外数组的乘积

除自身以外数组的乘积 medium 给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请**不要使用除法&a…

抖音seo矩阵系统源码搭建技术+二开开源代码定制部署

抖音SEO源码是指将抖音平台上的视频资源进行筛选、排序等操作&#xff0c;进而提升其在搜索排名中的权重&#xff0c;从而让更多的用户能够发现并观看到这些视频资源。而抖音SEO矩阵系统源码则是指通过建立一个分析系统&#xff0c;分析抖音中的用户、视频、标签等数据&#xf…

【数据分类】基于蜣螂优化算法优化支持向量机的数据分类方法 DBO-SVM分类算法【Matlab代码#47】

文章目录 【可更换其他群智能算法&#xff0c;获取资源请见文章第6节&#xff1a;资源获取】1. 蜣螂优化算法&#xff08;DBO&#xff09;2. 支持向量机&#xff08;SVM&#xff09;3. DBO-SVM分类模型4. 部分代码展示5. 仿真结果展示6. 资源获取 【可更换其他群智能算法&#…

Java Leetcode 动态规划 91. 解码方法

未优化版本代码展示&#xff1a; class Solution {public int numDecodings(String s) {char[]charss.toCharArray();int lengths.length();//创建dp数组int[]dpnew int[length];//初始化if(chars[0]!0){dp[0]1;}//特殊情况处理if(length1){return dp[0];}if(chars[1]!0){dp[1…

Postman高级应用——变量、流程控制、调试、公共函数、外部数据文件

目录 流程控制 调试 公共函数 外部数据文件 总结&#xff1a; Postman 提供了四种类型的变量 环境变量&#xff08;Environment Variable&#xff09; 不同的环境&#xff0c;使用不同的环境变量&#xff0c;例如&#xff1a;测试过程中经常会用到 测试环境&#xff0c;外…

PHP5.4以下解决json_encode中文UNICODE转码问题

PHP5.4以下解决json_encode中文UNICODE转码问题 把汉字先urlencode 然后再使用json_encode&#xff0c; json_encode之后 再次使用urldecode来解码&#xff0c; 这样编码出来的json数组中的 汉字就不会出现unicode编码了。 $params[importList][recipientAddress] urlencode(&…