java多线程 下

news2025/3/10 9:53:56

目录

线程的生命周期

 线程的同步

 Synchronized的使用方法

同步机制中的锁

同步的范围

 单例设计模式之懒汉式(线程安全)

 线程的死锁问题

Lock(锁)

synchronized 与 Lock 的对比 

线程的通信

JDK5.0 新增线程创建方式

新增方式一:实现Callable接口

新增方式二:使用线程池

总结


线程的生命周期

JDK中用Thread.State类定义了线程的几种状态

要想实现多线程,必须在主线程中创建新的线程对象。Java语言使用Thread类 及其子类的对象来表示线程,在它的一个完整的生命周期中通常要经历如下的

种状态

  • 新建: 当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态
  • 就绪:处于新建状态的线程被start()后,将进入线程队列等待CPU时间片,此时它已具备了运行的条件,只是没分配到CPU资源
  • 运行 :当就绪的线程被调度并获得CPU资源时,便进入运行状态., run()方法定义了线程的操作和功能
  • 阻塞:在某种特殊情况下,被人为挂起或执行输入输出操作时,让出 CPU 并临时中止自己的执行,进入阻塞状态
  • 死亡:线程完成了它的全部工作或线程被提前强制性地中止或出现异常导致结束

 线程的同步

问题的提出
  • 多个线程执行的不确定性引起执行结果的不稳定
  • 多个线程对账本的共享,会造成操作的不完整性,会破坏数据
class Ticket implements Runnable {
    private int tick = 100;
    public void run() {
        while (true) {
            if (tick > 0) {
                System.out.println(Thread.currentThread().getName() + "售出车票,tick为:"+                                                     tick--);
                }else
                 break;
        }
    }
}

class TicketDemo {
    public static void main(String[] args) {
        Ticket t = new Ticket();
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        Thread t3 = new Thread(t);
        t1.setName("t1窗口");
        t2.setName("t2窗口");
        t3.setName("t3窗口");
        t1.start();
        t2.start();
        t3.start();
    }
}

 

 

2. 问题的原因:

当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行。导致共享数据的错误。

3. 解决办法:

对多条操作共享数据的语句,.只能让一个线程都执行完,在执行过程中,其他线程不可以 参与执行

 

 Synchronized的使用方法

  Java对于多线程的安全问题提供了专业的解决方式: 同步机制
1. 同步代码块:
synchronized (对象){
// 需要被同步的代码;
}
2. synchronized还可以放在方法声明中,表示整个方法为 同步方法
例如: public synchronized void show (String name){ …. }  

同步机制中的锁

同步锁机制:

在《Thinking in Java》中,是这么说的:对于并发工作,你需要某种方式来防止两个任务访问相同的资源(其实就是共享资源竞争)。 防止这种冲突的方法就是当资源被一个任务使用时,在其上加锁。第一个访问某项资源的任务必须锁定这项资源,使其他任务在其被解锁之前,就无法访问它了,而在其被解锁之时,另一个任务就可以锁定并使用它了。

synchronized的锁是什么?

  • 任意对象都可以作为同步锁。所有对象都自动含有单一的锁(监视器)。
  • 同步方法的锁:静态方法(类名.class)、非静态方法(this
  • 同步代码块:自己指定,很多时候也是指定为this或类名.class

注意:

  •  必须确保使用同一个资源的多个线程共用一把锁,这个非常重要,否则就无法保证共享资源的安全
  • 一个线程类中的所有静态方法共用同一把锁(类名.class),所有非静态方 法共用同一把锁(this),同步代码块(指定需谨慎)

同步的范围

1 、如何找问题,即代码是否存在线程安全?(非常重要)
  • (1)明确哪些代码是多线程运行的代码
  • (2)明确多个线程是否有共享数据
  • (3)明确多线程运行代码中是否有多条语句操作共享数据
2 、如何解决呢?(非常重要)
对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中,其 他线程不可以参与执行。 即所有操作共享数据的这些语句都要放在同步范围中
3 、切记:
  • 范围太小:没锁住所有有安全问题的代码
  • 范围太大:没发挥多线程的功能。

释放锁的操作

当前线程的同步方法、同步代码块执行结束。

当前线程在同步代码块、同步方法中遇到breakreturn终止了该代码块、 该方法的继续执行。

当前线程在同步代码块、同步方法中出现了未处理的ErrorException,导致异常结束。

当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁

不会释放锁的操作

线程执行同步代码块或同步方法时,程序调用Thread.sleep()、Thread.yield()方法暂停当前线程的执行

线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程挂起,该线程不会释放锁(同步监视器)。 应尽量避免使用suspend()resume()来控制线程

 单例设计模式之懒汉式(线程安全)

class Singleton {
    private static Singleton instance = null;
    private Singleton(){}
    public static Singleton getInstance(){
        if(instance==null){
            synchronized(Singleton.class){
                if(instance == null){
                    instance=new Singleton();
        }
     } 
}
        return instance;

} }
public class SingletonTest{
    public static void main(String[] args){
        Singleton s1=Singleton.getInstance();
        Singleton s2=Singleton.getInstance();
        System.out.println(s1==s2);
        }
     }

 线程的死锁问题

死锁

不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁

出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续

解决方法

  • 专门的算法、原则
  • 尽量减少同步资源的定义
  • 尽量避免嵌套同步 

Lock()

JDK 5.0开始,Java提供了更强大的线程同步机制——通过显式定义同步锁对象来实现同步。同步锁使用Lock对象充当。

java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象。

ReentrantLock 类实现了 Lock ,它拥有与 synchronized 相同的并发性和 内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock,可以显式加锁、释放锁。

class A{
    private final ReentrantLock lock = new ReenTrantLock();
        public void m(){
            lock.lock();
                try{
                //保证线程安全的代码;
                } finally{
                lock.unlock(); 
            }
        }
    }

 注意:如果同步代码有异常,要将unlock()写入finally语句块

synchronized Lock 的对比 

相同:二者都可以解决线程安全问题
不同 synchronized机制在执行完相应的同步代码以后,自动释放同步监视器
     lock 需要手动的启动同步lock,同时结束也需要手动释放unlock

线程的通信

 class Communication implements Runnable {
    int i = 1;
    public void run() {
        while (true) {
            synchronized (this) {
                notify();
                if (i <= 100) {
                    System.out.println(Thread.currentThread().getName() +":" + i++);
                    } else
                     break;
                    try {
                        wait();
                      } catch (InterruptedException e) {
                        e.printStackTrace();
                }
            }
        }
    }
}
wait() notify() notifyAll()
  • wait():令当前线程挂起并放弃CPU、同步资源并等待,使别的线程可访问并修改共享资源,而当 前线程排队等候其他线程调用notify()notifyAll()方法唤醒,唤醒后等待重新获得对监视器的所有 权后才能继续执行。
  • notify():唤醒正在排队等待同步资源的线程中优先级最高者结束等待
  • notifyAll ():唤醒正在排队等待资源的所有线程结束等待.

这三个方法只有在synchronized方法或synchronized代码块中才能使用,否则会报java.lang.IllegalMonitorStateException异常。

因为这三个方法必须有锁对象调用,而任意对象都可以作为synchronized的同步锁,因此这三个方法只能在Object类中声明

wait() 方法

  • 在当前线程中调用方法: 对象名.wait()
  • 使当前线程进入等待(某对象)状态 ,直到另一线程对该对象发出 notify(或notifyAll) 为止。
  • 调用方法的必要条件:当前线程必须具有对该对象的监控权(加锁)
  • 调用此方法后,当前线程将释放对象监控权 ,然后进入等待
  • 在当前线程被notify后,要重新获得监控权,然后从断点处继续代码的执行。

notify()/notifyAll()

  • 在当前线程中调用方法: 对象名.notify()
  • 功能:唤醒等待该对象监控权的一个/所有线程。
  • 调用方法的必要条件:当前线程必须具有对该对象的监控权(加锁)

JDK5.0 新增线程创建方式

新增方式一:实现Callable接口

与使用Runnable相比, Callable功能更强大些

  • 相比run()方法,可以有返回值
  • 方法可以抛出异常
  • 支持泛型的返回值
  • 需要借助FutureTask类,比如获取返回结果

Future 接口
  • 可以对具体RunnableCallable任务的执行结果进行取消、查询是否完成、获取结果等。
  • FutrueTaskFutrue接口的唯一的实现类
  • FutureTask 同时实现了Runnable, Future接口。它既可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值

新增方式二:使用线程池

背景:经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大。

思路:提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁、实现重复利用。类似生活中的公共交通工具。

 好处:

  • 提高响应速度(减少了创建新线程的时间)
  • 降低资源消耗(重复利用线程池中线程,不需要每次都创建)
  • 便于线程管理  corePoolSize:核心池的大小   maximumPoolSize:最大线程数   keepAliveTime:线程没有任务时最多保持多长时间后会终止

线程池相关API

JDK 5.0起提供了线程池相关APIExecutorService Executors

  • ExecutorService:真正的线程池接口。常见子类ThreadPoolExecutor
  • void execute(Runnable command) :执行任务/命令,没有返回值,一般用来执行Runnable
  • <T> Future<T> submit(Callable<T> task):执行任务,有返回值,一般又来执行 Callable
  • void shutdown() :关闭连接池
  • Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池
  • Executors.newCachedThreadPool():创建一个可根据需要创建新线程的线程池
  • Executors.newFixedThreadPool(n); 创建一个可重用固定线程数的线程池
  • Executors.newSingleThreadExecutor() :创建一个只有一个线程的线程池
  • Executors.newScheduledThreadPool(n):创建一个线程池,它可安排在给定延迟后运行命令或者定期地执行

总结

package com.jyc.p1;

import java.util.concurrent.*;
import java.util.concurrent.locks.ReentrantLock;

/*
栗子:创建三个窗口卖票,总票为100张,使用实现 Runnable 接口的方式
    1.问题卖票过程中,出现了重票,错票---》线程安全问题
    2.问题出现的原因:在某个线程操作车票的过程中,尚未操作完成时,其他线程参与进来,也操作车票
    3.如何解决:当一个线程a在操作ticket的时候,其他线程不能参与进来,直到线程a操作完 ticket 时
其他线程才可以开始操作 ticket,这种情况线程a出现了阻塞,也不能被改变
    4.在java中我们通过同步机制,来解决线程的安全问题
        方式1.同步代码块
            synchronized (同步监视器){
                //需要被同步的代码
            }
          ①.操作共享数据的代码,即为需要同步的代码
          ②.共享数据,多个线程共同操作的变量,比如 ticket
          ③.同步监视器,俗称锁,任何一个类的对象,都可以充当锁(多个线程必须共用一把锁)
          ④ 在实现  Runnable 接口创建多线程的方式中,我们可以考虑使用this充当同步监视器
       方式2.同步方法
            如果操作共享数据的代码完整的声明在一个方法中,我们不妨将此方法声明为同步的
            同步方法仍是同步监视器,只是我们不需要显示的声明,
                非静态同步方法,同步监视器是this
                静态同步方法,同步监视器是当前类本身

     同步的方式,解决了线程的安全问题
     操作同步代码时,只能有一个线程参与,其他线程等待,相当于一个单线程的过程,效率低

    synchronized 与 lock 的异同
       相同:二者都可以解决线程安全问题
       不同 synchronized机制在执行完相应的同步代码以后,自动释放同步监视器
       lock 需要手动的启动同步lock,同时结束也需要手动释放unlock


* */
class window implements   Runnable{
    private    int ticket=100;
    Object obj= new Object();
//    方式一 :同步代码块
//    public void run() {
//        //此时的this 唯一的window对象
//        synchronized (this){//synchronized (obj){
//        while (true){
//            if (ticket>0){
//                try {
//                    Thread.sleep(100);
//                } catch (InterruptedException e) {
//                    e.printStackTrace();
//                }
//                System.out.println(Thread.currentThread().getName()+"卖票,票号为:"+ticket);
//                ticket--;
//            }else{
//                break;
//            }
//        }
//    }
//
//    }

//    方式三
//    1.实例化ReentrantLock
    private ReentrantLock lock=new ReentrantLock();
    public void run() {
//        while (true){
//            show();
//        }

        while (true){
            try{
                //调用锁定方法lock()
                lock.lock();

                if (ticket>0){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"卖票,票号为:"+ticket);
                    ticket--;
                }else{
                    break;
                }
            }finally {
                //调用解锁的方法unlock
                lock.unlock();
            }
        }
    }

    //方式二 同步方法
    private synchronized void  show(){ //同步监视器 this
        if (ticket>0){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"卖票,票号为:"+ticket);
                ticket--;
            }
    }
}
/*
* 单例模式 懒汉式
*
* */
class  Bank{
    private  Bank(){}
    private  static  Bank
            instance=null;
    //方式一.同步监视器为 Bank.class 类也为对象
//    public  static synchronized Bank getInstance(){
//        if (instance==null){
//            instance=new Bank();
//
//        }
//        return  instance;
    public  static  Bank getInstance(){
        if (instance==null){
            synchronized (Bank.class){
             if (instance==null){
                 instance=new Bank();
           }
       }
   }
        return  instance;
    }
}
/*
* 线程通讯的例子
* 涉及到三个方法
* wait() 一但执行此方法线程就进入阻塞状态,并释放同步监视器
* notify() 一但执行次此方法,就会唤醒wait的一个线程,如果有多个线程被wait就唤醒优先级高的那个
* notifyAll 一但执行次此方法,就会唤醒wait的所有线程
* 说明 wait notify notifyAll 这三个方法必须使用在同步代码块或同步方法中
*       三个方法的调用者必须是同步代码块,或同步方法中的同步监视器
*       定义在object中
*
* sleep 和 wait 的异同
*  相同点 一但 执行方法,都可以使当前线程进入阻塞状态,
*  不同点 1.两个方法声明的位置不同,Thread类中声明的sleep,object类中声明的wait
*         2. 调用的要求不同,sleep可以在任何场景下调用,wait方法必须使用在同步代码块或者同步方法中
*         3.关于是否释放同步监视器,如果两个方法都使用在同步代码块,或同步方法中,sleep()不会释放锁
*          wait()会释放锁
*
*
* */
class   Number implements  Runnable{
    private  int number=1;
    public void run() {
        while (true){
           synchronized (this){
               notify();
               if (number<=100){
                   try {
                       Thread.sleep(10);
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
                   System.out.println(Thread.currentThread().getName()+" : "+number);
                   number++;
                   try {
                       //使得调用如下wait()方法的线程进入阻塞状态
                       wait();
                   } catch (InterruptedException e) {
                       e.printStackTrace();
                   }
               }else{
                   break;
               }
           }

        }
    }
}

/*
*创建线程的方式三 实现 Callable 接口
*   如何理解实现 Callable接口的方式 比实现 Runnable 接口创建多线程的方式强大
*      call()可以有返回值
*      call()可以抛出异常
*      Callable 支持泛型
*
*
* */
//创建一个实现了 Callable 的实现类
class NumThread implements Callable{
    //实现call方法 将此线程需要执行的操作声明在call方法中

    @Override
    public Object call() throws Exception {
        int sum=0;
        for (int i = 1; i <=100 ; i++) {
            if(i%2==0){
                sum+=i;
            }
        }
        return  sum;
    }
}
/*

* */
public class Shkstart {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //演示线程安全问题------------
//        window w=new window();
//     Thread t1 =new Thread(w);
//        Thread t2 =new Thread(w);
//        Thread t3 =new Thread(w);
//        t1.setName("窗口一");
//        t2.setName("窗口二");
//        t3.setName("窗口三");
//        t1.start();
//        t2.start();
//        t3.start();
        //线程通讯的演示----------
//        Number number=new Number();
//        Thread t1=new Thread( number);
//        Thread t2=new Thread( number);
//        t1.setName("线程一");
//        t2.setName("线程二");
//        t1.start();
//        t2.start();

//        *创建线程的方式三 实现 Callable 接口---------------
        //3.创建实现Callable接口实现类的对象
        NumThread numThread=new NumThread();
        //4.将此Callable接口实现的对象 传递到 FutureTask 构造器中 创建 FutureTask 对象
        FutureTask futureTask = new FutureTask(numThread);
        //5.将 FutureTask的对象作为参数 传递到 Thread类的构造器中并调用start
       new Thread(futureTask).start();
        Object sum= futureTask.get();
        //6.获取 Callable中 call方法的返回值
        System.out.println(sum);

//        * 创建线程的方式四 使用线程池
        // 提高响应速度(减少了创建新线程的时间)
        // 降低资源消耗(重复利用线程池中线程,不需要每次都创建)
        // 便于线程管理
        // corePoolSize:核心池的大小
        // maximumPoolSize:最大线程数
        // keepAliveTime:线程没有任务时最多保持多长时间后会终止

        //1.提供指定线程数量的线程池
        ExecutorService service=Executors.newFixedThreadPool(10);
//        设置线程池的属性

        //2.执行指定线程的操作实现 Callable或 Runnable 的对象
//        service.submit()
//        service.execute();
        //3.关闭链接池
        service.shutdown();
    }
}

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

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

相关文章

利用LSTM识别显式篇章关系实战 可作为毕设

1.显式篇章关系分类概述 案例知识点: 任务描述:篇章关系分析是自然语言中处理篇章级基础语言分析任务,其目的是利用规则或机器学习等计算机处理手段判别篇章各组成成分之间的修辞逻辑关系,从而从整体上理解篇章。其中论元之间有连接词连接的此类关系称为显式篇章关系。本教…

RabbitMQ实战教程

RabbitMQ实战教程1.什么是RabbitMQ1.1 MQ&#xff08;Message Queue&#xff09;消息队列1.1.1 异步处理1.1.2 应用解耦1.1.3 流量削峰1.2 背景知识介绍1.2.1 AMQP高级消息队列协议1.2.2 JMS1.2.3 二者的联系1.2.4 Erlang语言1.3 为什么选择RabbitMQ1.4 RabbitMQ各组件功能2.怎…

【springboot 2.5.14 +jsp】打jar包,超详细,亲测可用,带源码

【springboot 2.5.14 jsp】打jar包&#xff0c;案例文档目录截图文件配置文件pom.xmlapplication.xmljspindex.jspjavaSpringbootJspApplication.javaHelloController.java打包方式运行源码地址文档目录截图 文件 配置文件 pom.xml <?xml version"1.0" encodi…

VEML6075的驱动代码

VEML6075的驱动代码VEML6075简介VEML6075相关参数VEML6075IIC读写相关时序VEML6075IIC读写驱动代码VEML6075IIC读写串口打印总结VEML6075简介 VEML6075是一种紫外线&#xff08;UV&#xff09;光传感器&#xff0c;它可以测量紫外线强度。它通常用于各种应用&#xff0c;包括环…

【云原生 | Kubernetes 实战】15、K8s 控制器 Daemonset 入门到企业实战应用

目录 一、DaemonSet 控制器&#xff1a;概念、原理解读 1.1 DaemonSet 概述 1.2 DaemonSet 工作原理&#xff1a;如何管理 Pod &#xff1f; 1.3 Daemonset 典型的应用场景 1.4 DaemonSet 与 Deployment 的区别 二、DaemonSet 资源清单文件编写技巧 三、DaemonSet …

零基础如何自学Python编程?

零基础如何系统地自学Python编程&#xff1f;绝大多数零基础转行者学习编程的目的就是想找一份高薪有发展前景的工作&#xff0c;哪个编程语言就业前景好越值得学习。零基础的同学学Python是一个不错的选择。 对于零基础的初学者最迷茫的是不知道怎样开始学习&#xff0c;建议…

基础背包问题--0 1背包与完全背包

&#x1f389;&#x1f389;&#x1f389;写在前面&#xff1a; 博主主页&#xff1a;&#x1f339;&#x1f339;&#x1f339;戳一戳&#xff0c;欢迎大佬指点&#xff01; 目标梦想&#xff1a;进大厂&#xff0c;立志成为一个牛掰的Java程序猿&#xff0c;虽然现在还是一个…

JS基于base64编码加密解密文本和图片

JS基于base64编码加密解密文本和图片 ​ 密码学&#xff0c;体系太庞大了&#xff0c;常见的加密解密算法很多&#xff0c;我仅了解了一下&#xff0c;这里仅介绍采用实现base64加密解密的方法。 严格地说base64不是加密算法&#xff0c;他只是一种编码方式&#xff0c;是一…

企业经营管理的核心是什么?

一、企业经营管理是什么&#xff1f; 企业经营管理通常是指&#xff0c;企业为了满足自身生存发展&#xff0c;通过对企业内部成员的经营活动进行计划、组织、协调、指挥、控制。企业经营管理主要目的是为了让企业在面向市场和用户是时&#xff0c;可以充分利用企业自身优势和…

excel日期函数:如何计算项目的开始和完成日期

制定工作计划是我们平时工作中经常会遇到的一类事务&#xff0c;例如某个项目&#xff0c;需要分成七个阶段来完成&#xff0c;已知项目的开始日期和每个项目需要的时间&#xff08;以天为单位&#xff09;&#xff0c;就可以做出一个项目的工作计划表&#xff1a; 需要重点强调…

无约束优化:修正阻尼牛顿法

文章目录无约束优化&#xff1a;修正阻尼牛顿法梯度法的困难经典牛顿法定义收敛性证明修正阻尼牛顿法考虑修正阻尼牛顿法的起因如何构造修正矩阵M参考文献无约束优化&#xff1a;修正阻尼牛顿法 梯度法的困难 无约束优化&#xff1a;线搜索最速下降 对于光滑函数而言&#x…

pg 锁机制深析

spin lock 使用 cas 去获取锁&#xff0c;先获取 spins_per_delay 次数&#xff0c;如果还失败&#xff0c;则每次获取失败将 delay 时长延长至 1~2倍 delay 值加 0.5 us&#xff0c;spins_per_delay 的值在获取锁后会做更新&#xff0c;如果这次没有等待&#xff0c;则下次可…

Python可视化——matplotlib.pyplot绘图的基本参数详解

目录 1.matplotlib简介 2.图形组成元素的函数用法 2.1. figure()&#xff1a;背景颜色 2.2 xlim()和 ylim()&#xff1a;设置 x&#xff0c;y 轴的数值显示范围 2.3 xlabel()和 ylabel()&#xff1a;设置 x&#xff0c;y 轴的标签文本 2.4 grid()&#xff1a;绘制刻度线的…

NVIDIA深度学习基础-理论与实践入门课程笔记及测验参考代码

1. 使用MNIST数据集进行图像分类 1.1 MNIST数据集 在深度学习的历史当中,对 MNIST 数据集里的70000张手写体数字的图像进行0到9的正确分类是一个重大的进展。如今,这个问题被认为是微不足道的,但是使用 MNIST 进行图像分类已经成为深度学习的一个 Hello World 练习。 以下…

TDC-GP30固件升级笔记

Bootloader介绍 系统重置或系统INIT发生后&#xff0c;总是请求引导加载程序。但是&#xff0c;只有在设置了引导加载器发布代码时&#xff0c;才会执行引导加载器操作。 Bootloader操作包括&#xff1a; “Register Configuration” 寄存器配置”&#xff0c;将配置数据传输…

8-Arm PEG-DBCO分子量决定外观性状,用于修饰生物分子

英文名称&#xff1a;8-Arm PEG-DBCO 中文名称&#xff1a;八臂-聚乙二醇-二苯基环辛炔 分子量&#xff1a;1k&#xff0c;2k&#xff0c;3.4k&#xff0c;5k&#xff0c;10k&#xff0c;20k&#xff08;可按需定制&#xff09; 质量控制&#xff1a;95% 存储条件&#xff…

计算机毕设Python+Vue学校教务管理系统(程序+LW+部署)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

计算机中丢失vcruntime140_1.dll,要怎么修复这个问题

关于计算机中丢失vcruntime140_1.dll其实是非常的常见的&#xff0c;当出现这种情况的时候&#xff0c;不需要担心&#xff0c;其实有好多种方法可以解决的。 解决丢失vcruntime140_1.dll的方法 第一种方法&#xff1a;既然计算机丢失了这个vcruntime140_1.dll文件&#xff0…

git:合并多个commit

目录1. 查看提交记录2. 合并commit3. 查看合并后的日志记录1. 查看提交记录 git log --oneline --graph2. 合并commit 这里希望合并最后3个commit&#xff08;modify1&#xff0c;modify2&#xff0c;modify3&#xff09; git rebase -i idid需要使用倒数第4个commit的id&am…

【docker】安装MySQL

实战&#xff1a;安装MySQL 思考&#xff1a;MySQL的数据持久化的问题 #获取镜像 docker pull mysql:5.7 #运行容器&#xff0c;需要做数据挂载 #安装启动MySQL&#xff0c;需要配置密码&#xff08;docker Hub&#xff09; #官方测试 docker run --name some-mysql -e MYSQL…