javaSE(九):线程

news2024/11/19 17:20:00

目录

一、程序,进程,线程

1.概念

2.三者之间的关系:

二、创建线程

①继承Thread类的方式

②实现Runnable接口的方式

三、Thread类中方法

1.常用方法

 2.线程优先级

四、线程状态

①线程在它的生命周期中会处于不同的状态

②线程的状态

五、多线程

1.概念

2.何时需要多线程

3.多线程的优点

4.多线程的缺点

六、线程同步

1.多线程同步

2.同步就是排队+锁

3.例题

①继承Thread 类

 ②实现Runnable接口

4.同步锁机制

5.同步锁

6.同步执行过程

七、Lock(锁)

八、线程通信

1.例题引入

2.概念

3.经典例题:生产者/消费者问题

九、新增创建线程方式


一、程序,进程,线程

1.概念

程序(program)是为完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码.

进程((process)正在内存中运行的应用程序,如运行中的QQ,运行中的音乐播 放器。进程是操作系统进行资源分配的最小单位.

线程(thread)进程可进一步细化为线程,是一个进程内部的最小执行单元,是操作系统进行任务调度的最小单元,隶属于进程.

2.三者之间的关系:

一个进程可以包含多个线程;

● 一个线程只能属于一个进程,线程不能脱离进程而独立运行;

● 每一个进程至少包含一个线程(称为主线程);

● 在主线程中可以创建并启动其它的线程;

● 一个进程内的所有线程共享该进程的内存资源;

public class Demo {
    public static void main(String[] args) {
          /*
          此段程序只能按照从上向下的顺序执行
          因为是单线程的,只有main这一个程序
          */

        System.out.println("main开始执行");
        methodA();
        methodB();
        System.out.println("main结束执行");
    }

    public static void methodA(){
        System.out.println("methodA");
    }

    public static void methodB(){
        System.out.println("methodB");
    }

}

 输出结果:

main开始执行
methodA
methodB
main结束执行

二、创建线程

①继承Thread类的方式

●在Java中要实现线程,最简单的方式就是扩展Thread类,重写其中的run方法,方法原型如下:

● Thread类中的run方法本身并不执行任何操作,如果我们重写了run方法,当线程启动时,它将执行run方法。

public class MyThread extends Thread {
    /*
    java中创建线程方式1:
       写一个类继承java.lang.Thread
       重写run()
    */
    /*
      线程中要执行的任务都要写在run()中,或者在run()中进行调用
    */
    @Override
    public void run() {
        this.test();
    }

    public void test(){
        for (int i = 0; i < 1000; i++) {
            System.out.println("MyThread:"+i);
        }
    }

 public static void main(String[] args) {
        //创建并启动线程
        MyThread myThread = new MyThread();
       // myThread.run();//这不是启动线程,只是一个方法的调用,没有启动线程,还是单线程模式的
        myThread.start();

        for (int i = 0; i < 1000; i++) {
            System.out.println("main:"+i);
        }
    }

}

 输出部分结果展示:

②实现Runnable接口的方式

● java.lang.Runnable接口中仅仅只有一个抽象方法:

 

●也可以通过实现Runnable接口的方式来实现线程,只需要实现其中的run方法即可;

● Runnable接口的存在主要是为了解决Java中不允许多继承的问题。

 /*java中创建线程方式2:
        只先创建要执行的任务,创建一个类,实现Runnable接口
        重写任务执行中的run
 */

public class Task implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("自定义线程:"+i);
        }
    }

public static void main(String[] args) {
        //创建任务
        Task task = new Task();
        //创建线程,并为线程指定执行任务
        Thread thread = new Thread(task);
        thread.start();

        for (int i = 0; i < 1000; i++) {
            System.out.println("main:"+i);
        }
    }

}

 输出部分结果展示:

 


【实现Runnable接口创建的优点】
    1)因为java是单继承,一旦继承一个类就不能继承其他类,避免单继承的局限性
    2)多个线程可以共享同一个接口实现类的对象,适合多线程来处理同一份资源使用


三、Thread类中方法

1.常用方法

Thread类中的方法:

1.线程中要执行的任务都要写在run()中

run(); 用来定义线程要执行的任务代码
currentThread(); 获取当前线程
getId(); 获取线程的id
getName();获取线程的名字
getPriority();获取线程优先级
getState();获取线程状态
sleep(); 让线程阻塞休眠指定的时间
yield();主动礼让 退出cpu

2.创建线程对象时调用的方法

start(); 启动线程的
setPriority();设置线程优先级  优先级为1-10,默认是5,作用是为操作系统调度算法提供的
setName();为线程设置名字
join();等待调用了join()线程执行完毕,其他线程再执行
public class MyThread extends Thread {

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getId());
            System.out.println(Thread.currentThread().getName());
            System.out.println(Thread.currentThread().getName()+":"+Thread.currentThread().getPriority());
            System.out.println(Thread.currentThread().getState());
        }
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        Thread thread = Thread.currentThread();//获取当前正在执行的程序
        System.out.println(thread.getName());

     for (int i = 0; i < 100; i++) {
            Thread thread = Thread.currentThread();//获取当前正在执行的线程
            if (i%10 ==0) {
                Thread.yield();//主动礼让 退出cpu
            }
            System.out.println(thread.getName()+":"+i);
        }
    }
}
public class ThreadTest {

    public static void main(String[] args) throws InterruptedException {
        
        MyThread myThread = new MyThread();
        System.out.println(myThread.getState());
        myThread.setName("窗口1");
        myThread.setPriority(5);
        myThread.start();
       // myThread.join();//等待调用了join()线程执行完毕,其他线程再执行
        System.out.println(myThread.getState());

        MyThread myThread1 = new MyThread();
        myThread1.setName("窗口2");
        myThread1.setPriority(1);
        myThread1.start();
    }
}

 2.线程优先级

● 事实上,计算机只有一个CPU,各个线程轮流获得CPU的使用权,才能执行任务;

● 优先级较高的线程有更多获得CPU的机会,反之亦然;

● 优先级用整数表示,取值范围是1~10,一般情况下,线程的默认优先级都是5,但是也可以通过setPriority和getPriority方法来设置或返回优先级;

●调度策略

①时间片

②抢占式:高优先级的线程抢占CPU

●Java的调度方法

 ①同优先级线程组成先进先出队列,使用时间片策略

②对高优先级,使用优先调度的抢占式策略

● Thread类有如下3个静态常量来表示优先级

 ①MAX_PRIORITY:取值为10,表示最高优先级。

 ②MIN_PRIORITY:取值为1,表示最底优先级。

 ③NORM_PRIORITY:取值为5,表示默认的优先级。

四、线程状态

①线程在它的生命周期中会处于不同的状态

②线程的状态

新建:当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态

就绪:处于新建状态的线程被start()后,将进入线程队列等待CPU时间片,此时它已具备了运行的条件,只是没分配到CPU资源

运行:当就绪的线程被调度并获得CPU资源时,便进入运行状态,run()方法定义了线程的操作和功能

●阻塞:在某种特殊情况下,被人为挂起或执行输入输出操作时,让出CPU并临时中止自己的执行,进入阻塞状态


运行到阻塞状态:

①sleep()

    try {
          Thread.sleep(200);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

②join()

MyThread myThread = new MyThread();
        System.out.println(myThread.getState());
        myThread.setName("窗口1");
        myThread.setPriority(5);
        myThread.start();
        myThread.join();//等待调用了join()线程执行完毕,其他线程再执行
        System.out.println(myThread.getState());

③Scanner 控制台输入

Scanner scanner = new Scanner(System.in);
        scanner.nextInt();

④等待同步锁

⑤wait() 

阻塞到就绪状态:

①sleep()时间到

②调用了join线程执行完了

③用户在控制台已输入

④获取同步锁

⑤notify(),其他线程唤醒


●死亡:线程完成了它的全部工作或线程被提前强制性地中止或出现异常导致结束


运行到死亡状态:

①执行完run()

②调出线程的stop()

③出现异常并未处理

 System.out.println(10/0);//线程中出现异常,并没有处理——死亡
        for (int i = 0; i < 100; i++) {
            Thread thread = Thread.currentThread();//获取当前正在执行的线程
            if (i%10 ==0) {
                Thread.yield();//主动礼让 退出cpu
            }
            System.out.println(thread.getName()+":"+i);
        }

五、多线程

1.概念

多线程是指程序中包含多个执行单元,即在一个程序中可以同时运行多个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行执行的线程来完成各自的任务。

2.何时需要多线程

● 程序需要同时执行两个或多个任务。

● 程序需要实现一些需要等待的任务时,如用户输入、文件读写操作、 网络操作、搜索等。

3.多线程的优点

● 提高程序的响应.

● 提高CPU的利用率.

● 改善程序结构,将复杂任务分为多个线程,独立运行

4.多线程的缺点

● 线程也是程序,所以线程需要占用内存,线程越多占用内存也越多;

● 多线程需要协调和管理,所以需要跟踪管理线程,使得cpu开销变大;

● 线程之间同时对共享资源的访问会相互影响,如果不加以控制会导致数据出错.

六、线程同步

1.多线程同步

多个线程同时读写同一份共享资源时,可能会引起冲突。所以引入线程“同步”机制, 即各线程间要有先来后到;

2.同步就是排队+锁

● 几个线程之间要排队,一个个对共享资源进行操作,而不是同时进行操作;

● 为了保证数据在方法中被访问时的正确性,在访问时加入锁机制

3.例题

模拟卖票,两个窗口分别售票,票数为10张,分别使用继承Thread和实现Runnable两种方式实现

继承Thread 类

synchronized同步代码块

public class TicketThread extends Thread{
     static int num = 10;//模拟有10张票
     static  Object obj = new Object();

   /*
      synchronized (同步锁对象){
            同步代码块
      }
   */

    @Override
    public void run() {
       while(true){
          synchronized (obj){//obj对象作用:记录有没有线程进入到同步代码块  要求:多个线程对应同一个同步锁对象
              if (num>0) {
                  try {
                      Thread.sleep(100);
                  } catch (InterruptedException e) {
                      throw new RuntimeException(e);
                  }
                  System.out.println(Thread.currentThread().getName()+"买到了第"+num+"张票");
                  num--;
              }else{
                  break;
              }
          }

        }
    }

     public static void main(String[] args) {

        TicketThread t1 = new TicketThread();
        t1.setName("窗口1");
        t1.start();

        TicketThread t2 = new TicketThread();
        t2.setName("窗口2");
        t2.start();
    }

}

synchronized同步方法 

public class TicketThread extends Thread{
     static int num = 10;//模拟有10张票

    @Override
    public void run() {
        while(true){
        if (num<=0){
            break;
        }
        print();
        }
    }

    public static synchronized void print(){
        if (num>0) {
            System.out.println(Thread.currentThread().getName()+"买到了第"+num+"张票");
            num--;
        }
    }

     public static void main(String[] args) {

        TicketThread t1 = new TicketThread();
        t1.setName("窗口1");
        t1.start();

        TicketThread t2 = new TicketThread();
        t2.setName("窗口2");
        t2.start();
    }

}

 实现Runnable接口

synchronized同步代码块

public class TicketTask implements Runnable {

    int num = 10;

    @Override
    public void run() {
         while(true){
                synchronized (this){
                    if (num>0) {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                        System.out.println(Thread.currentThread().getName()+"买到了第"+num+"张票");
                        num--;
                    }else{
                        break;
                    }
                }
           }
    }
     public static void main(String[] args) {
        //只需要创建一个出票任务
        TicketTask ticketTask = new TicketTask();

        Thread t1 = new Thread(ticketTask);
        t1.setName("窗口1");
        t1.start();

        Thread t2 = new Thread(ticketTask);
        t2.setName("窗口2");
        t2.start();
    }
}

synchronized同步方法 

public class TicketTask implements Runnable {

    int num = 10;

    @Override
    public void run() {
        while(true){
            if (num<=0){
                break;
            }
            this.print();
        }
    }

    public synchronized void print(){
        if (num>0) {
            System.out.println(Thread.currentThread().getName()+"买到了第"+num+"张票");
            num--;
        }
    }
     public static void main(String[] args) {
        //只需要创建一个出票任务
        TicketTask ticketTask = new TicketTask();

        Thread t1 = new Thread(ticketTask);
        t1.setName("窗口1");
        t1.start();

        Thread t2 = new Thread(ticketTask);
        t2.setName("窗口2");
        t2.start();
    }

}

 输出结果:

4.同步锁机制

确保一个时间点只有一个线程访问共享资源。可以给共享资源加一把锁,哪个线程获取了这把锁,才有权利访问该共享资源。

● 在Java代码中实现同步:

使用synchronized(同步锁对象)关键字同步代码块

synchronized (同步锁){

// 需要被同步的代码;

 }

synchronized还可以放在方法声明中,表示整个方法,为同步方法

public synchronized void show (String name){

 // 需要被同步的代码;

}

5.同步锁

同步锁可以是任何对象,必须唯一,保证多个线程获得是同一个对象(用来充当锁标记).

6.同步执行过程

①第一个线程访问,锁定同步对象,执行其中代码.

②第二个线程访问,发现同步对象被锁定,无法访问.

③第一个线程访问完毕,解锁同步对象.

④第二个线程访问,发现同步对象没有锁,然后锁定并访问.

七、Lock(锁)

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

• java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。

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

public class TicketThread extends Thread{

    static int num = 10;
    static ReentrantLock  reentrantLock = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            try {
                reentrantLock.lock();//0-1  加锁
                if (num > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    System.out.println(Thread.currentThread().getName() + "买到了第" + num + "张票");
                    num--;
                } else {
                    break;
                }
            } finally {
                reentrantLock.unlock();//1-0 释放锁
            }
        }
    }
     public static void main(String[] args) {

        TicketThread t1 = new TicketThread();
        t1.setName("窗口1");
        t1.start();

        TicketThread t2 = new TicketThread();
        t2.setName("窗口2");
        t2.start();
    }

}


     synchronized 和 reentrantLock区别:
         synchronized是一个关键字,控制依靠底层编译后的指令执行去实现
         synchronized可以修饰一个方法,还可以修饰一个代码块
         synchronized是隐式的加锁和释放锁,一旦方法和代码块中运行结束或出现异常,会自动释放锁

         reentrantLock是一个类,是依靠java代码去控制(底层有一个同步队列)
         reentrantLock只能修饰代码块
         reentrantLock需要手动的加锁,手动的释放锁,所以释放锁最好写在finally中,一旦出现异常,保证锁能释放
    

八、线程通信

1.例题引入

● 两个线程交替打印1-100之间的数字

public class PrintNumThread extends Thread{

    static int num = 1;
    static  String obj = new String();//同步锁

    @Override
    public void run() {
        while(num<100){
            synchronized (obj){
                obj.notify();//唤醒等待的线程
                System.out.println(Thread.currentThread().getName()+":"+num);
                num++;
                try {
                    obj.wait();//让线程等待,会自动地释放锁, notify(),wait(),必须在同步代码块中使用,必须是通过锁对象调用的
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }

    }
     public static void main(String[] args) {
        PrintNumThread p1 = new PrintNumThread();
        p1.start();

        PrintNumThread p2 = new PrintNumThread();
        p2.start();
    }
}

 输出部分结果:

2.概念

线程通讯指的是多个线程通过相互牵制,相互调度,即线程间的相互作用。

涉及三个方法:

①wait一旦执行此方法,当前线程就进入阻塞状态,并释放同步锁对象。

②notify一旦执行此方法,就会唤醒被wait的一个线程。如果有多个线程被wait, 就唤醒优先级高的那个。

③notifyAll一旦执行此方法,就会唤醒所有被wait的线程。


!!!注意:

wait(),notify(),notifyAll()三个方法必须使用在同步代码块同步方法


3.经典例题:生产者/消费者问题

● 生产者(Productor)将产品放在柜台(Counter),而消费者(Customer)从柜台处取走产品,生产者一次只能生产固定数量的产品(比如:1), 这时柜台中不能 再放产品,此时生产者应停止生产等待消费者拿走产品,此时生产者唤醒消费者来 取走产品,消费者拿走产品后,唤醒生产者,消费者开始等待

分别创建四个类CustmoerThread消费者线程;ProductorThread生产者线程;Counter柜台用于添加,拿走商品;Test用于测试,创建线程

public class CustmoerThread extends Thread{

    Counter counter;

    public CustmoerThread (Counter counter){
        this.counter = counter;
    }

    @Override
    public void run() {
        while(true){//消费者线程一直消费
            try {
                this.counter.sub();
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
public class ProductorThread extends Thread {

    Counter counter;

    public  ProductorThread(Counter counter){
        this.counter = counter;
    }

    @Override
    public void run() {
        while(true){//生产者线程一直生产
            try {
                this.counter.add();
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
//柜台
public class Counter {

     static int num = 1;//柜台可以存放的商品数量

     //生产者线程调用 添加商品
     public synchronized void add() throws InterruptedException {//锁对象是this,两个方法共用一把锁
          if (num==0){
              this.notify();
              num=1;
               System.out.println("生产者线程生产了一件商品");
          }else{
               this.wait();
          }
     }
     //消费者线程调用 拿走商品
     public synchronized void sub() throws InterruptedException {
          if (num>0){
               this.notify();
               num=0;
               System.out.println("消费者线程消费了一件商品");
          }else{
               this.wait();
          }
     }

}
public class Test {
    public static void main(String[] args) {

        Counter counter = new Counter();//只创建一个柜台对象

        ProductorThread productorThread = new ProductorThread(counter);
        productorThread.setName("生产者线程");

        CustmoerThread custmoerThread = new CustmoerThread(counter);
        custmoerThread.setName("消费者线程");

        productorThread.start();
        custmoerThread.start();
    }
}

输出结果:

九、新增创建线程方式

实现Callable接口与使用Runnable相比,Callable功能更强大些.

• 相比run()方法,可以有返回值

• 方法可以抛出异常

• 支持泛型的返回值

• 需要借助FutureTask类,获取返回结果

接收任务

FutureTask futureTask = new FutureTask(任务);

创建线程

Thread t = new Thread(futureTask);

t.start();

Integer val = futureTask.get();获得线程call方法的返回值

public class SumTask<T> implements Callable<T> {


    @Override
    public T call() throws Exception {
        Integer n = 0;
        for (int i = 0; i < 10; i++) {
            n+=i;
        }
        Thread.sleep(1000);
        return (T)n;
    }
     public static void main(String[] args) throws ExecutionException, InterruptedException {
        SumTask<Integer> sumTask = new SumTask();
        FutureTask<Integer> futureTask = new FutureTask<>(sumTask );
        Thread thread = new Thread(futureTask);
        thread.start();

        Integer sum = futureTask.get();//获取call方法返回的执行结果
        System.out.println(sum);
    }
}

输出结果:

45

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

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

相关文章

君正X2100 RTOS 固件升级

使用cloner工具烧写固件需要在上电之前让boot_sel[2:0]处于boot from USB模式&#xff0c;但是电路板装在机壳内部后不方便改变boot_sel[2:0]的状态&#xff0c;如果要升级固件&#xff0c;需要通过机壳留出的USB口、网口、或者无线网络进行固件更新。 一、升级方案 1、固件分…

vivado Versal 串行 I/O 硬件调试流程、使用 Vivado Serial I/O Analyzer 来调试设计

Versal 串行 I/O 硬件调试流程 Versal ™ ACAP 无需再生成 IBERT IP &#xff0c; 因为使用系统内串行 I/O 调试所需的必要逻辑现已集成到 GTY 收发器架构内。使 用 GTY 收发器的任何设计均可用于串行 I/O 硬件调试。 Versal 串行 I/O 硬件调试流程具有 2 个不同阶…

10.JAVAEE之网络编程

1.网络编程 通过网络,让两个主机之间能够进行通信 >基于这样的通信来完成一定的功能进行网络编程的时候,需要操作系统给咱们提供一组 AP1, 通过这些 API才能完成编程&#xff08;API 可以认为是 应用层 和 传输层 之间交互的路径&#xff09;&#xff08;API:Socket API相当…

【Qt常用控件】—— QWidget 核心属性

目录 &#xff08;一&#xff09;控件概述 1.1 关于控件体系的发展 &#xff08;二&#xff09;QWidget 核心属性 2.1 核心属性概览 2.2 enabled 2.3 geometry 2.4 windowTitle 2.5 windowIcon 2.6 windowOpacity 2.7 cursor 2.8 font 2.9 toolTip 2.10 focus…

java的ArrayList LinkedList的操作

文章目录 ArrayList1. ArrayList集合的特点2. 操作 LinkedList1. LinkedList集合的特点2. 操作 参考链接 ArrayList 1. ArrayList集合的特点 2. 操作 add(Object element) 向列表的尾部添加指定的元素。size() 返回列表中的元素个数。get(int index) 返回列表中指定位置的元素…

Git ignore、exclude for TortoiseGit 小结

1.Ignore Type&#xff1a;忽略类型&#xff0c;也即忽略规则&#xff0c;如何去忽略文件? 1.1.Ignore item(s) only in containing folder(s)&#xff1a;仅忽略在包含在文件夹中项目。 仅忽略该文件夹下选定的patterns。the patterns其实就是文件类型&#xff0c;比如.txt后…

MATLAB循环语句

MATLAB 循环语句 在某些情况下&#xff0c;您需要多次执行一个代码块。通常&#xff0c;语句是按顺序执行的。首先执行函数中的第一条语句&#xff0c;然后执行第二条&#xff0c;依此类推。 编程语言提供了各种控制结构&#xff0c;允许更复杂的执行路径。 循环语句允许我们…

把 KubeBlocks 跑在 Kata 上,真的可行吗?

背景 容器的安全性一直是广受关注的话题。这个领域也产生了很多不错的开源项目。Kata就是其中之一。 Kata Containers&#xff08;简称 Kata&#xff09;是一种开源项目&#xff0c;它提供了一种安全而高性能的容器运行时环境。Kata Containers 利用虚拟化技术&#xff08;通常…

【深度学习实战(24)】如何实现“断点续训”?

一、什么是断点续训&#xff1a; 中断的地方&#xff0c;继续训练。与加载预训练权重有什么区别呢&#xff1f;区别在于优化器参数和学习率变了。 二、如何实现“断点续训” 我们需要使用checkpoint方法保存&#xff0c;模型权重&#xff0c;优化器权重&#xff0c;训练轮数…

TablePlus for Mac/Win:开启高效数据开发新纪元

在当今数字化时代&#xff0c;数据的重要性日益凸显。无论是企业还是个人&#xff0c;都需要一款强大而实用的本地原生数据开发软件来提升工作效率。而 TablePlus for Mac/Win 正是这样一款卓越的工具&#xff0c;它为用户带来了全新的体验&#xff0c;让数据开发变得更加轻松、…

【HarmonyOS4学习笔记】《HarmonyOS4+NEXT星河版入门到企业级实战教程》课程学习笔记(三)

课程地址&#xff1a; 黑马程序员HarmonyOS4NEXT星河版入门到企业级实战教程&#xff0c;一套精通鸿蒙应用开发 &#xff08;本篇笔记对应课程第 4 - 6节&#xff09; P5《04.快速入门》 本节来实现一个 HelloWorld 效果&#xff1a; 1、打开编辑器&#xff0c;选择新建项目&…

【matlab】reshape函数介绍及应用

【matlab】reshape函数介绍及应用 【先赞后看养成习惯】求点赞关注收藏&#x1f600; 在MATLAB中&#xff0c;reshape函数是一种非常重要的数组操作函数&#xff0c;它可以改变数组的形状而不改变其数据。本文将详细介绍reshape函数的使用方法和应用。 1. reshape函数的基本语…

Redisson分布式锁 --- 源码分析

1.获取一把锁 RLock lock redissonClient.getLock("订单lock"); 2.业务代码加锁 lock.lock(); 2.1 lock.tryAcquire Long ttl tryAcquire(leaseTime, unit, threadId); 2.2 lua脚本: tryLockInnerAsync方法 如果获取锁失败&#xff0c;返回的结果是这个key的剩…

ssm项目搭建,springboot项目搭建

一、springboot项目搭建 1.新建一个文件夹用idea打开 2.配置maven工作目录、jdk路径、编码方式 3.pom.xml依赖管理&#xff1a;不同的项目&#xff0c;只需要修改下面的三行就可以 <groupId>com.qcby</groupId> <artifactId>HXQ0419</artifactId> &l…

如何安装、升级英伟达显卡驱动

目录 方式一&#xff1a;GeForce Experience 方式二&#xff1a;英伟达官网手动下载驱动 在做深度学习的过程中&#xff0c;难免会使用到cudatoolkit&#xff0c;而cudatoolkit又需要跟英伟达显卡驱动适配。比如笔者使用的电脑目前安装的英伟达显卡驱动 Driver Version: 516.…

git的安装与配置教程--超详细版

一、git的安装 1. 官网下载git git官网地址&#xff1a;https://git-scm.com/download/win/ 选择需要的版本进行下载 2、下载完成之后&#xff0c;双击下载好的exe文件进行安装。 3、默认是C盘&#xff0c;推荐修改一下路径&#xff0c;然后点击下一步 4、Git配置&#xff…

Java虚拟机(jvm)常见问题总结

1.电脑怎样认识我们编写的Java代码 首先先了解电脑是二进制的系统&#xff0c;他只认识 01010101比如我们经常要编写 HelloWord.java 电脑是怎么认识运行的HelloWord.java是我们程序员编写的&#xff0c;我们人可以认识&#xff0c;但是电脑不认识 Java文件编译的过程 1. 程…

4.25日学习记录

[HZNUCTF 2023 preliminary]ppppop 对于php反序列化&#xff0c;在之前的学习中有过了解&#xff0c;但是对于序列化字符串的格式不是很了解&#xff0c;刚好接触这题&#xff0c;可以了解一下 序列化字符串的格式&#xff1a; 布尔型&#xff08;bool&#xff09;b&#xf…

bugfix: com.alibaba.druid.sql.parser.EOFParserException: EOF

前言 在日常的开发工作中&#xff0c;我们经常会遇到各种各样的问题&#xff0c;其中涉及数据库操作的接口联调尤其容易出现意想不到的状况。今天我就遇到了一个关于Druid SQL解析异常的问题&#xff0c;具体表现为com.alibaba.druid.sql.parser.EOFParserException: EOF。通过…

盲人使用公共设施:科技助力无障碍出行与智能识别

在我们的日常生活中&#xff0c;公共设施扮演着不可或缺的角色&#xff0c;它们为人们提供了便利的服务&#xff0c;构建起和谐、高效的社会环境。然而&#xff0c;对于视障人士而言&#xff0c;尽管公共设施设计之初便考虑到通用性和包容性&#xff0c;实际使用过程中仍难免遭…