Java中Thread类的基本认识与使用(如果想知道Java中有关Thread类的基本知识,那么只看这一篇就足够了!)

news2024/10/26 19:17:04

        前言:在Java中,Thread类是实现多线程编程的核心。它允许程序同时执行多个任务,提高应用程序的响应能力和性能。通过Thread类,开发者可以轻松创建和管理线程,并实现复杂的并发操作。接下来,我们将探讨Thread类的基本用法及其在实际开发中的应用。


✨✨✨这里是秋刀鱼不做梦的BLOG

✨✨✨想要了解更多内容可以访问我的主页秋刀鱼不做梦-CSDN博客

在开始讲解并查集之前,先让我们看一下本文大致的讲解内容:

目录

1.Java中线程的回顾

2.Thread线程的五种创建方式

        (1)继承 Thread 类创建线程

        (2)实现 Runnable 接口创建线程

        (3)使用匿名内部类创建 Thread 子类对象

        (4)使用匿名内部类创建 Runnable 子类对象

        (5)使用 Lambda 表达式创建线程

3.多线程的状态与调度

        (1)线程状态

        (2)线程调度

4.Thread类的属性及基本方法的使用

        【1】Thread类的基本属性

        (1)线程 ID(ID)

        (2)线程名称(Name)

        (3)线程状态(State)

        (4)线程优先级(Priority)

        (5)后台线程(Daemon)

        (6)线程存活状态(Alive)

        (7)线程中断标志(Interrupted)

        【2】Thread类的常用方法

        (1)启动一个线程 - start()

        (2)中断一个线程 - interrupt()      

        (3)等待一个线程 - join()

        (4)获取当前线程引用 - Thread.currentThread()

        (5)休眠当前线程 - Thread.sleep()


1.Java中线程的回顾

        线程是程序中执行代码的最小单位,通常被称为执行流。每个线程都有自己独立的运行路径,并且可以与其他线程并行执行代码。多个线程共享同一进程的资源,比如内存空间和文件句柄,但它们之间可以独立调度。

        ——这就像在现实生活中,我们有多个员工(线程)在公司(进程)里同时工作,虽然他们共享办公空间和资源,但每个人都有各自的任务要完成。

        在程序中,线程能够提高并发性,处理多任务,减少等待时间。线程的概念可以通过如下的代码理解:

public class ThreadDemo {
    private static class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + "正在运行");
        }
    }

    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();

        t1.start(); // 启动第一个线程
        t2.start(); // 启动第二个线程
    }
}

        在这个例子中,MyThread 类继承了 Thread,我们通过 start() 方法启动了两个线程 t1t2,它们分别执行各自的任务。线程可以独立运行,即使它们共享相同的进程资源。

        

        ——所以我们为什么需要线程来帮助我们工作呢?

        多线程编程的需求主要来自两个方面:提高多核CPU的利用率处理I/O等待问题

  1. 提高多核CPU的利用率 随着硬件的发展,CPU的单核性能提升遇到了瓶颈,现代的计算机通常采用多核CPU。为了充分利用这些多核资源,程序需要能够并行处理多个任务,这时多线程编程就成为了一个关键手段。例如,如果一个程序能够同时在多个CPU核心上运行不同的线程,整体计算效率就会成倍提升。

  2. 解决I/O等待问题 有时,程序需要等待某些耗时的I/O操作(如文件读写或网络请求)完成,而在等待这些操作时,CPU的资源可能会被浪费掉。通过引入多线程,程序可以在等待I/O时继续执行其他任务,从而提高整体效率。就像在餐馆里,厨师可以同时准备多道菜,而不是等待每道菜完成后再开始下一个。

        这里我们在使用一个日常生活中的例子来进行理解:

        假设你在银行办理业务,需要分别处理财务转账、员工福利发放、社保缴纳。如果只有一个员工来处理所有这些事务,他需要排队等候多个业务完成,这会拖慢整个流程。而如果每个业务都有专门的员工负责,它们可以同时进行,显著提高效率。这就是多线程在程序中的表现。

       ——通过上述的回顾,我相信读者已经可以回想起有关Java中线程的内容了!!!

2.Thread线程的五种创建方式

        回顾完有关Java中线程的知识之后,让我们正式的开始本篇文章的主要内容,那么一开始,让我们先看一下在Java中如何去创建一个线程,其有以下五种创建方式:

        (1)继承 Thread 类创建线程

        这是最直接的方式,通过继承 Thread 类并重写其 run() 方法来定义线程的执行逻辑。Thread 类本身实现了 Runnable 接口,因此每个 Thread 对象都可以被当作一个线程。通过调用 start() 方法,线程会开始运行,操作系统的线程调度器会选择适当的时机执行 run() 方法中的代码。

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("线程 " + Thread.currentThread().getName() + " 正在执行");
    }
}

public class ThreadExample {
    public static void main(String[] args) {
        MyThread thread1 = new MyThread(); // 创建线程对象
        thread1.start(); // 启动线程
    }
}

该种方式创建线程的优点:

  • 简单直观,适合需要对线程本身进行自定义控制的场景

该种方式创建线程的缺点:

  • Java 不支持多继承,如果线程类已经继承了其他类,就不能再继承 Thread 类,因此这种方式具有局限性。

        (2)实现 Runnable 接口创建线程

        相比继承 Thread 类,实现 Runnable 接口 是更灵活的方式,因为它解耦了线程的任务与线程对象本身。通过实现 Runnable 接口并将其传递给 Thread 对象,我们可以实现类似的功能。这种方式尤其适合在需要继承其他类时使用。

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("线程 " + Thread.currentThread().getName() + " 正在执行");
    }
}

public class RunnableExample {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable); // 创建线程对象并传入 Runnable 对象
        thread.start(); // 启动线程
    }
}

该种方式创建线程的优点:

  • 线程任务与线程对象分离,符合面向接口编程的原则。

  • 适用于需要继承其他类的场景,更加灵活。

该种方式创建线程的缺点:

  • 与直接继承 Thread 相比,代码稍显复杂,需要额外的 Runnable 对象。

        (3)使用匿名内部类创建 Thread 子类对象

        为了简化代码,Java 提供了匿名内部类的方式来创建线程对象。这种方式通过定义一个匿名子类并重写 run() 方法,可以在一行代码中同时创建线程并指定其任务。匿名内部类适合用于短小的、一次性的线程任务。

public class AnonymousThreadExample {
    public static void main(String[] args) {
        // 使用匿名类创建 Thread 子类对象
        Thread thread = new Thread() {
            @Override
            public void run() {
                System.out.println("匿名类线程 " + Thread.currentThread().getName() + " 正在执行");
            }
        };
        thread.start(); // 启动线程
    }
}

该种方式创建线程的优点:

  • 代码简洁,适合一次性任务,避免创建额外的类文件。

该种方式创建线程的缺点:

  • 可读性较差,特别是对于复杂任务时,不易维护。

  • 由于是匿名类,不能复用或扩展其功能。

        (4)使用匿名内部类创建 Runnable 子类对象

        类似于匿名 Thread 子类的方式,匿名内部类 也可以用于创建 Runnable 对象,然后将其传递给 Thread。这种方式依然能够通过实现 Runnable 接口来定义线程任务,并保持代码简洁

public class AnonymousRunnableExample {
    public static void main(String[] args) {
        // 使用匿名类创建 Runnable 子类对象
        Runnable myRunnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("匿名类 Runnable 线程 " + Thread.currentThread().getName() + " 正在执行");
            }
        };
        
        Thread thread = new Thread(myRunnable); // 创建并启动线程
        thread.start();
    }
}

该种方式创建线程的优点:

  • 灵活且代码简洁,能够避免创建多余的类文件。

  • 线程任务与 Thread 对象分离,保持了良好的代码结构。

该种方式创建线程的缺点:

  • 可读性较差,对于复杂任务的实现不够清晰。

  • 匿名内部类不能被复用。

        (5)使用 Lambda 表达式创建线程

        在 Java 8 之后,Lambda 表达式大大简化了代码的书写。当任务逻辑较为简单时,可以用 Lambda 表达式代替匿名内部类来实现 Runnable 接口。Lambda 表达式使代码更简洁、易读,同时避免了不必要的语法冗余。

public class LambdaThreadExample {
    public static void main(String[] args) {
        // 使用 Lambda 表达式创建 Runnable 对象
        Thread thread = new Thread(() -> {
            System.out.println("Lambda 线程 " + Thread.currentThread().getName() + " 正在执行");
        });

        thread.start(); // 启动线程
    }
}

该种方式创建线程的优点:

  • 代码极其简洁,尤其适合简单的线程任务。

  • 提升代码的可读性,减少样板代码的编写。

该种方式创建线程的缺点:

  • 仅适用于 Java 8 及以上版本。

  • 不适合需要大量逻辑或复杂任务的场景。

        ——以上就是Java中创建线程的五种方式了!!!

3.多线程的状态与调度

        了解了Java中的线程如何去创建之后,现在让我们深入Java中的Thread类,看看其状态和其如何去调度的。

        (1)线程状态

        了解完了如何在Java中去创建一个线程之后,在让我们看一下Java中的线程的状态以及调度,在Java中,线程的生命周期可以分为五种状态:

  1. NEW(新建状态):线程对象被创建,但尚未调用 start() 方法,此时线程还未开始运行。

  2. RUNNABLE(可运行状态):线程已经调用 start() 方法,进入就绪队列,等待CPU的调度,或者正在运行中。

  3. BLOCKED(阻塞状态:线程等待获取锁时处于阻塞状态。比如当线程试图进入一个 synchronized 块但锁被其他线程占用时,它就会进入 BLOCKED 状态。

  4. WAITING(等待状态):线程主动等待某个条件的触发,比如调用了 wait() 方法,等待其他线程调用 notify()

  5. TERMINATED(终止状态):线程执行完毕或被异常终止,此时线程已经结束运行。

这里我们使用一段代码来对线程的状态进行控制并打印其状态:

public class ThreadStateDemo {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            for (int i = 0; i < 1000000; i++) { /* 模拟任务执行 */ }
        });

        System.out.println("线程状态:" + thread.getState());  // NEW
        thread.start();
        while (thread.isAlive()) {
            System.out.println("线程状态:" + thread.getState());  // RUNNABLE
        }
        System.out.println("线程状态:" + thread.getState());  // TERMINATED
    }
}

        在这个代码中,线程 thread 在不同时刻有不同的状态:NEW 表示线程刚刚创建,RUNNABLE 表示线程正在运行,TERMINATED 表示线程已经执行完毕(读者可能不太理解其中的方法,不管美食,读者只要根据该代码对上述的线程状态进行理解即可)

        (2)线程调度

        线程的调度由操作系统的线程调度器管理,Java中的线程调度是抢占式的,这意味着线程的执行顺序由系统决定,而不是由程序直接控制。操作系统会根据线程的优先级、系统负载等因素来决定哪个线程获得CPU的时间片。

        因此,线程的执行顺序是不确定的,这也是为什么在多线程编程中会出现一些竞争问题,后面我们将进一步讨论。

        这样我们就了解了有关多线程的状态与调度了。

4.Thread类的属性及基本方法的使用

        通过上述的讲解,我们相信读者已经对Java中的线程有了初步的理解了,那么现在开始,我们就开始学习Java中Thread类的属性和操作Java中线程的方法了。

        【1】Thread类的基本属性

        在Java中 Thread 类有一些重要的属性,它们用于表示和控制线程的状态和行为,理解这些属性有助于更好地调试和优化多线程程序,以下是 Thread 类中的几个常见属性:

        (1)线程 ID(ID)

        每个线程都有一个唯一的ID,表示线程的标识符。这个ID是系统自动分配的,且不同线程的ID永远不会重复。线程ID用于唯一标识每个线程,无论线程是否运行,ID都可以帮助我们区分不同的线程。开发者可以通过 getId() 方法获取线程的ID:

long id = thread.getId();
System.out.println("线程 ID: " + id);

        线程ID主要用于低级别的系统操作或调试,它是线程的唯一标识符,不能被更改。

        (2)线程名称(Name)

        线程名称是开发者可以手动指定的属性。通过设置有意义的名称,开发者可以在调试或日志中快速定位某个线程的执行情况。线程的名称可以在创建时指定,也可以在运行过程中通过 setName() 方法更改:

thread.setName("WorkerThread");
String name = thread.getName();
System.out.println("线程名称: " + name);

        线程名称不影响线程的执行逻辑,但它对开发者了解线程的功能和状态起到重要作用,特别是在多线程调试中非常有用。

        (3)线程状态(State)

        线程状态表示线程当前的执行状态,Thread.State 是一个枚举类型,包含了线程的几种典型状态,如 NEW(新建)、RUNNABLE(可运行)、BLOCKED(阻塞)、WAITING(等待)、TIMED_WAITING(计时等待)和 TERMINATED(终止)。开发者可以通过 getState() 方法获取线程的当前状态:

Thread.State state = thread.getState();
System.out.println("线程状态: " + state);

        线程状态的变化能够帮助开发者理解线程的生命周期和调度行为,尤其是在遇到阻塞或死锁问题时,状态信息能够提供有力的调试依据。

        (4)线程优先级(Priority)

        每个线程都有一个优先级,范围从 1 到 10。线程优先级是操作系统用来调度线程的一个参考值,优先级高的线程更有可能获得 CPU 时间片。开发者可以通过 setPriority()getPriority() 方法来设置和获取线程的优先级:

thread.setPriority(Thread.MAX_PRIORITY);
int priority = thread.getPriority();
System.out.println("线程优先级: " + priority);

        尽管优先级会影响线程的调度顺序,但并不能保证线程优先级较高的线程一定会首先执行,因为线程调度最终由操作系统控制。

        (5)后台线程(Daemon)

        后台线程,也称为守护线程,是一种特殊的线程类型。当所有非后台线程结束时,JVM 会自动退出,即使后台线程仍然在运行。典型的后台线程包括垃圾回收线程,它们在系统后台执行一些不需要用户直接干预的操作。可以通过 setDaemon(true) 来将一个线程设置为后台线程:

thread.setDaemon(true);
boolean isDaemon = thread.isDaemon();
System.out.println("是否为后台线程: " + isDaemon);

        后台线程非常适合用于执行长期运行且不依赖于用户输入的任务,例如监控、清理任务等。但需要注意的是,JVM 退出时后台线程会被强制停止,可能导致任务未能完全执行完毕。

        (6)线程存活状态(Alive)

        一个线程在调用 start() 方法之后即被视为“存活”,直到它的 run() 方法执行完毕或者被强制中断后才会结束。开发者可以通过 isAlive() 方法检查线程是否仍在运行:

boolean isAlive = thread.isAlive();
System.out.println("线程是否存活: " + isAlive);

        线程的存活状态能够帮助开发者判断一个线程是否已经结束执行,这在需要等待线程完成任务时非常有用。

        (7)线程中断标志(Interrupted)

        当一个线程被其他线程调用 interrupt() 方法时,它会被标记为中断状态。线程可以通过 isInterrupted()interrupted() 方法来检查自身是否被中断:

thread.interrupt();  // 中断线程
boolean isInterrupted = thread.isInterrupted();
System.out.println("线程是否被中断: " + isInterrupted);

        中断通常用于停止线程的执行,特别是在需要安全终止线程时,开发者可以通过捕获 InterruptedException 来终止阻塞中的线程操作(例如 sleep())。

        以上就是Java中线程的一些基本属性了!!!

        【2】Thread类的常用方法

        (1)启动一个线程 - start()

        在 Java 中,创建了一个 Thread 对象并不意味着线程会立即执行。线程的创建仅仅是分配了一些系统资源,但要让线程真正开始执行,还需要调用 start() 方法。当 start() 方法被调用时,线程进入到 可运行状态RUNNABLE),然后等待被系统的线程调度器选中并执行其 run() 方法。

        注意: 直接调用 run() 方法不会启动新线程,它只是将 run() 方法当作普通的方法来执行,运行在当前调用线程中。真正启动线程的方式是调用 start() 方法,它会在 JVM 中真正创建一个新线程。

以下为一个代码案例:

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + " 线程正在执行");
    }
}

public class ThreadStartExample {
    public static void main(String[] args) {
        MyThread thread = new MyThread();  // 创建线程
        System.out.println("线程状态:" + thread.getState());  // NEW
        thread.start();  // 启动线程
        System.out.println("线程状态:" + thread.getState());  // RUNNABLE
    }
}

在上面的代码中,线程在 start() 调用后,从 新建状态NEW)切换为 可运行状态RUNNABLE),此时线程可以被操作系统调度并执行。

        (2)中断一个线程 - interrupt()      

        在多线程编程中,有时需要安全地停止一个正在执行的线程。Java 提供了 interrupt() 方法,用于通知线程停止执行。需要注意的是,interrupt() 并不会强制终止线程,而是通过设置线程的中断状态来通知线程自己是否应该终止。

        线程可以通过检查其中断状态来决定是否结束运行。如果线程正在执行阻塞操作(如 sleep()wait()),那么 interrupt() 会导致这些操作抛出 InterruptedException,从而跳出阻塞状态并执行相应的终止逻辑。

以下为一个代码案例:

public class ThreadInterruptExample {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            try {
                for (int i = 0; i < 5; i++) {
                    System.out.println(Thread.currentThread().getName() + " 正在执行");
                    Thread.sleep(1000);  // 模拟工作
                }
            } catch (InterruptedException e) {
                System.out.println(Thread.currentThread().getName() + " 被中断");
            }
        });

        thread.start();
        Thread.sleep(3000);  // 主线程等待3秒
        thread.interrupt();  // 中断线程
    }
}

thread.interrupt() 会中断线程,使得 sleep() 操作抛出 InterruptedException,从而线程终止。

        (3)等待一个线程 - join()

        有时候,在主线程或其他线程中,我们希望等待某个线程执行完毕再继续执行后续操作。此时,可以使用 join() 方法。join() 会让调用线程进入 等待状态,直到目标线程执行完毕或达到指定的等待时间(如果提供了超时参数)。通过 join() 方法,我们可以确保一个线程在另一个线程执行完成之后才继续执行。

以下为一个代码案例: 

public class ThreadJoinExample {
    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(() -> {
            for (int i = 0; i < 3; i++) {
                System.out.println(Thread.currentThread().getName() + " 正在工作");
                try {
                    Thread.sleep(1000);  // 模拟工作
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + " 工作完成");
        });

        Thread thread2 = new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + " 准备开始工作");
        });

        thread1.start();
        thread1.join();  // 主线程等待 thread1 完成
        thread2.start();  // 只有 thread1 完成后,thread2 才会启动
    }
}

在这个例子中,主线程会调用 thread1.join() 来等待 thread1 完成,只有当 thread1 执行完毕后,thread2 才会开始执行。

        (4)获取当前线程引用 - Thread.currentThread()

        在多线程编程中,有时我们需要获取当前正在执行的线程对象。Java 提供了静态方法 Thread.currentThread(),它返回对当前线程的引用。通过这个方法,开发者可以获取当前线程的名称、ID、优先级等属性,或对当前线程进行操作(例如检查中断状态)。

public class CurrentThreadExample {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            // 获取当前线程引用
            Thread currentThread = Thread.currentThread();
            System.out.println("当前线程名称: " + currentThread.getName());
        });

        thread.start();
        
        // 获取主线程的引用
        Thread mainThread = Thread.currentThread();
        System.out.println("主线程名称: " + mainThread.getName());
    }
}

在这个示例中,我们使用了 Thread.currentThread() 获取当前线程的引用,并打印了线程的名称。无论是在新启动的线程中还是主线程中,这个方法都可以用于获取当前执行线程的相关信息。

        (5)休眠当前线程 - Thread.sleep()

        在多线程编程中,常常需要让线程在某些时刻暂停执行一段时间。Java 提供了 Thread.sleep() 方法,可以让线程进入 休眠状态。线程在休眠期间不会占用 CPU 资源,但它仍然保持着某些锁定状态。当休眠时间结束后,线程会恢复到 就绪状态,等待 CPU 的调度。

        需要注意的是,sleep() 可能会抛出 InterruptedException,因此在调用时通常需要处理该异常。

public class ThreadSleepExample {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            try {
                System.out.println(Thread.currentThread().getName() + " 开始休眠");
                Thread.sleep(3000);  // 线程休眠3秒
                System.out.println(Thread.currentThread().getName() + " 休眠结束");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        thread.start();
    }
}

在这个例子中,线程通过 Thread.sleep() 休眠了 3 秒钟,然后继续执行剩下的代码。sleep() 的休眠时间是最低限制,也就是说,线程休眠的时间可能会比指定的时间稍长,因为休眠结束后线程需要等待系统的调度。

        以上是关于如何启动、等待、获取当前线程、休眠和中断线程的详细解释,这些操作都是 Java 多线程编程中常用的基本方法,希望读者可以根据上述的案例以及讲解对Java中的Thread的类有自己独到的理解!


以上就是本篇文章的全部内容了~~~

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

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

相关文章

Java中自增自减,赋值,逻辑,三元运算符

自增自减运算符 在某个变量前面或者后面加一--在某个变量前面或者后面减一 可以看见&#xff0c;当a输出时&#xff0c;a是没有变化的&#xff0c;说明如果是在变量后就是先使用再增加&#xff0c;而b输出时&#xff0c;b增加了1&#xff0c;说明如果是在变量前面就是先增加再…

机器人转人工时,开启实时质检(mod_cti基于FreeSWITCH)

文章目录 前言联系我们实现步骤1. 修改拨号方案2. 启用拨号方案 前言 在客户与机器人对话中&#xff0c;是不能开启质检功能的。因为机器人识别会与质检识别产生冲突。如果用户想通过机器人转接到人工时&#xff0c;开启质检功能&#xff0c;记录客户与人工之间的对话。应该如…

《a16z : 2024 年加密货币现状报告》解析

加密社 原文链接&#xff1a;State of Crypto 2024 - a16z crypto译者&#xff1a;AI翻译官&#xff0c;校对&#xff1a;翻译小组 当我们两年前第一次发布年度加密状态报告的时候&#xff0c;情况跟现在很不一样。那时候&#xff0c;加密货币还没成为政策制定者关心的大事。 比…

Python Numpy 实现神经网络自动训练:反向传播与激活函数的应用详解

Python Numpy 实现神经网络自动训练&#xff1a;反向传播与激活函数的应用详解 这篇文章介绍了如何使用 Python 的 Numpy 库来实现神经网络的自动训练&#xff0c;重点展示了反向传播算法和激活函数的应用。反向传播是神经网络训练的核心&#xff0c;能够通过计算梯度来优化模…

unity项目导出安卓工程后,在AndroidStudio打包报错:unityLibrary:BuildIl2CppTask‘.

下面这个是我在unity开发者社区提问后&#xff0c;他们回答得&#xff1a; 解决方案&#xff1a;我这边按照这几个方案检查了下&#xff0c;NDK和JDK都没问题&#xff0c;最后重启电脑才解决的&#xff0c;应该是文件被锁定了&#xff0c;我用的windows系统的。 验证&#xff…

达梦数据守护集群_备库重建(二)

目录 1、概述 1.1 实验场景 1.2 实验环境 2、故障模拟 3、重建方案1 3.1 登录主库、联机备份 3.2 脱机还原备库 3.3 模拟新业务数据 3.4 主库备份归档 3.5 利用归档恢复备库 3.6 启动备库 3.7 验证 4、重建方案2 4.1 登录主库、联机备份 4.2 脱机还原备库 4.3 …

是否有必要考PG认证?

如今PG很火,我在BOSS招聘查了一下,确实很多职位需要PG.那么考个PG认证确实很有必要! 当然这么快给出肯定答案,这公众号是发不出来的.必须有300个字才可以哦! 大家友情支持下,点点广告! 听我来细说 1.2.3 本小仙40有余可以说是80后.我们这代80后什么好事都没捞着,糟糕的事没有…

基于docker 部署redis

1、拉取镜像 docker pull redis:latest如果拉取失败可以尝试下配置镜像源&#xff0c;具体参考如下&#xff0c;目前暂可以使用 Docker切换镜像源-CSDN博客 2、创建配置文件 mkdir /usr/local/redis/conf vim redis.conf bind 0.0.0.0#protected-mode no port 6379 tcp-b…

用更多的钱买电脑而不是手机

如果&#xff0c;我们对自己的定义是知识工作者&#xff0c;那么在工作、学习相关的电子设备投入上&#xff0c;真的别舍不得花钱。 需要留意的是&#xff0c;手机&#xff0c;对于大部分在电脑前工作的人&#xff0c;不是工作设备。在我看来&#xff0c;每年投入到电脑的钱&…

前端经典【面试题】持续更新HTML、CSS、JS、VUE、FLUTTER、性能优化等

HTML/CSS 面试题 什么是语义化 HTML&#xff1f; 说明&#xff1a;语义化 HTML 使用 HTML 标签来描述内容的含义&#xff0c;而不仅仅是其外观。使用语义化标签可以提高可读性和可访问性&#xff0c;并对 SEO 友好。示例&#xff1a; <header><h1>网站标题</h1&…

基于C#开发游戏辅助工具的Windows底层相关方法详解

开发游戏辅助工具通常需要深入了解Windows操作系统的底层机制&#xff0c;以及如何与游戏进程进行有效交互。本文将基于C#语言&#xff0c;从Windows底层方法的角度来详细讲解开发游戏辅助工具的相关技术和概念。 一、游戏辅助工具的基本概述 游戏辅助工具&#xff0c;通常被称…

Java应用程序的测试覆盖率之设计与实现(三)-- jacoco cli 客户端

一、背景 上文已把覆盖率数据采集好了,并提供远程连接的tcp地址及端口。 jacoco cli文档jacoco cli jar包jacococli.jar 我下载好了,放在github工程里。 本文主要是介绍如何使用jacoco cli 客户端读取并生成覆盖率报告。 二、使用 1、dump覆盖率统计 java -jar doc/jacoc…

duilib的应用 在双屏异分辨率的显示器上 运行显示不出来

背景&#xff1a;win11&#xff0c;duilib应用&#xff0c;双显示器&#xff0c;两台分辨率相同&#xff0c;分别设置不同的缩放以后&#xff0c;应用运行以后&#xff0c;程序闪一下消失或者程序还在&#xff0c;但是UI显示不出来。 原因 窗口风格设置不合理&#xff0c;所以…

【办公类-57-01】美工室材料报销EXCEL表批量插入截图(图片)

背景需求&#xff1a; 我们班分到美工室&#xff0c;需要准备大量材料&#xff0c;根据原始的报销单EXCLE&#xff0c;里面有商品名称、图片、链接、单位、数量等信息 今天我和搭档一起填写新表&#xff0c;发现手机截图的图片插入EXCEL后非常大&#xff0c; 需要手动调整图片…

alovajs:前后端交互还能这么玩?

嘿&#xff0c;小伙伴们&#xff01;今天我要和大家分享一个超级有趣的发现。最近在折腾项目时&#xff0c;我遇到了一个叫 alovajs 的工具&#xff0c;它居然能帮我们构建 Client-Server 交互层&#xff01;听起来有点高大上&#xff0c;但其实超级实用。一起来探索这个新大陆…

JS+Springboot做一个交互Demo

背景&#xff1a;老大做了一个 SDK&#xff0c;包含字符加解密、文件加解密&#xff0c;要求能从前端访问&#xff0c;并且能演示的 Demo。 思路&#xff1a;html 写页面&#xff0c;js 发送请求&#xff0c;freemarker 做简单的参数交互&#xff0c;JAVA 后端处理。 一、项目依…

element 按钮变形 el-button样式异常

什么都没动&#xff0c;element UI的按钮变形了&#xff0c;莫名其妙&#xff0c;连官网的也变形了&#xff0c;换了其它浏览器又正常&#xff0c; 难道这是element UI的问题&#xff1f;NO&#xff0c;是浏览器的插件影响到了&#xff01;去扩展插件里面一个个关闭扩展&#x…

使用高德API和MapboxGL实现路径规划并语音播报

概述 本文使用高德API实现位置查询和路径规划&#xff0c;使用MapboxGL完成地图交互与界面展示&#xff0c;并使用Web Speech API实现行驶中路线的实时语音播报。 效果 Web Speech API简介 Web Speech API 使你能够将语音数据合并到 Web 应用程序中。Web Speech API 有两个部…

软件测试的重要一环:「性能测试」怎么做?

性能测试是软件测试中的重要一环&#xff0c;今天给大家介绍性能测试及如何使用RunnerGo完成性能测试任务。 性能测试是什么&#xff1f; 一句话概括&#xff1a;不断地通过不同场景的系统表现去探究系统设计与资源消耗之间的平衡&#xff0c;为开发人员提供消除瓶颈所需的诊…

IntelliJ IDEA 设置数据库连接全局共享

前言 在日常的软件开发工作中&#xff0c;我们经常会遇到需要在多个项目之间共享同一个数据库连接的情况。默认情况下&#xff0c;IntelliJ IDEA 中的数据库连接配置是针对每个项目单独存储的。这意味着如果你在一个项目中配置了一个数据库连接&#xff0c;那么在另一个项目中…