⛳ Java多线程 一,线程基础

news/2024/7/4 21:13:16/文章来源:https://blog.csdn.net/weixin_53456849/article/details/132051163

线程基础

  • ⛳ Java多线程 一,线程基础
  • 🐾 一,线程基础
      • 💭 1.1,什么是程序,进程,线程
      • 🏭 1.2,什么是并行和并发
      • 👣 1.3,线程使用的场景
      • 🎨 1.4,创建线程
        • 1.4.1,继承 `Thread`类的方式
        • 1.4.2,实现`Runanble`接口:
        • 1.4.3,`Thread` 常见方法
        • 1.4.4,`sleep()`方法
        • 1.4.5,线程优先级
        • 1.4.6,守护线程
        • 1.4.7,线程合并
        • 1.4.8,线程退出
      • 📢 1.5,线程的生命周期
        • 1.5.1,线程的调度与时间片
        • 1.5.2,线程状态
        • 1.5.3,多线程自增 i++ 和线程执行原理

⛳ Java多线程 一,线程基础

当涉及多线程编程时,我们可以同时执行多个任务,从而提高程序的性能和响应性。然而,多线程编程也带来了一些挑战,比如线程同步和资源共享。在本教程中,我们将介绍Java中的多线程编程,包括创建和管理线程,线程同步,以及常见的多线程问题和解决方案。

🐾 一,线程基础

💭 1.1,什么是程序,进程,线程

在计算机科学中,程序(Program),进程(Process)和线程(Thread)是三个重要的概念,它们都与执行计算机任务和程序相关。

  1. 程序(Program):

    程序是一系列指令的集合,这些指令按照特定的顺序组织,用于完成特定的任务或执行特定的操作。程序是静态的,它们只是存储在计算机磁盘或存储设备中,并不直接执行。当我们想要运行一个程序时,操作系统会将程序加载到内存中,并将其转换为进程,然后才能执行其中的指令。

  2. 进程(Process):

    进程是计算机程序在执行时的实例。它是计算机中正在运行的程序的活动副本。每个进程都有自己独立的内存空间,包含程序代码、数据、堆栈等信息。进程之间相互隔离,一个进程的崩溃不会影响其他进程的稳定性。每个进程在操作系统中都有自己的标识符(Process ID),它可以用来管理和监控进程的状态。

    进程有以下特点:

    • 进程之间相互隔离,一个进程的崩溃不会影响其他进程的稳定性。每个进程在操作系统中都有自己的标识符(Process ID),它可以用来管理和监控进程的状态。
    • 资源分配:每个进程拥有自己的内存空间和系统资源。
    • 切换开销:在进程之间切换会导致一定的开销,因为需要保存和恢复各个进程的上下文。
    1. 线程(Thread):

      线程是进程中的执行单元,每个进程可以包含多个线程。线程与进程共享相同的内存空间,因此它们可以更轻松地相互通信。多线程在多核处理器上能够实现并行执行,从而提高程序的性能和响应性。

      线程有以下特点:

      • 共享资源:线程之间共享进程的内存和资源,可以更方便地交换数据和信息。

      • 轻量级:相较于进程,线程的创建、切换和销毁开销较小。

      • 同步问题:多线程共享资源可能导致同步问题,需要采取同步机制来避免数据冲突。

        总结:

        程序是一组指令的集合,进程是程序在执行时的实例,而线程是进程中的执行单元。进程之间相互独立,而线程共享同一进程的资源。多线程在并行处理和提高程序性能方面具有优势,但同时也需要注意处理线程同步问题。

🏭 1.2,什么是并行和并发

并行(Parallel /ˈpærəlel/ )和并发(Concurrent /kənˈkʌrənt/)是两个与计算机执行任务相关的重要概念。

  1. 并行(Parallel):

    并行是指同时执行多个任务或操作。在计算机中,当多个处理器核心或计算单元同时执行不同的任务或同一个任务的不同部分时,我们称之为并行执行。这样可以显著提高计算机系统的处理能力和效率,特别时在多核处理器上。

    举例来说,如果有一个任务要处理一系列的数据,那么在并行处理中,不同的处理器核心可以同时处理这些数据的不同部分,从而更快地完成任务。

  2. 并发(Concurrent):

    并发是指同时处理多个任务,但并不一定是同时执行这些任务。在计算机中,并发执行是通过快速的任务切换和调度来实现的,操作系统会以非常小的时间片轮流执行多个任务,让它们看起来是同时进行的。

    举例来说,如果有两个任务要处理,操作系统可以分别给它们分配时间片,让它们交替执行,从用户的角度来看,好像这两个任务在同时进行。

    关键区别: 并行是真正的同时执行多个任务,需要多个处理器核心或计算单元支持。而并发是通过快速的切换和调度,让多个任务交替执行,从用户的角度来看,好像这些任务在同时进行,但实际上是在时间上错开的。

    总结:

    并行是真正的同时执行多个任务,利用多核处理器等技术提高计算效率;而并发是通过任务切换和调度,让多个任务交替执行,实现任务间的快速切换,从用户角度看起来是同时执行的。并行适合利用多核处理器等资源来加速计算,而并发适合在单核处理器上实现任务的高效利用。

👣 1.3,线程使用的场景

线程在计算机编程和软件开发中有许多使用场景。

它们主要用于以下情况:

  1. 并发执行:线程使得程序能够同时处理多个任务,特别是在多核处理器上能够实现真正的并行执行。例如,一个计算密集型的应用程序可以将任务分成多个线程,在多核处理器上同时执行,提高整体性能。
  2. 多任务处理:线程可以用于在单个应用程序内执行多个任务,使得程序能够同时响应多个用户请求或事件。例如,一个服务器应用程序可以使用多线程来同时处理多个客户端请求。
  3. 用户界面响应:在图形用户界面(GUI)应用程序中,线程用于保持用户界面的响应性。将耗时的任务(如文件加载、网络请求等)放在后台线程中执行,以免阻塞用户界面的操作。
  4. 并行算法:在某些计算密集型任务中,可以使用线程实现并行算法,将计算任务分成多个部分并在不同线程中并行执行,从而加快计算速度。
  5. 服务器应用:在服务器端应用程序中,线程用于同时处理多个客户端连接请求,实现高并发处理能力。
  6. 多媒体处理:在音频、视频处理等应用中,线程可用于同时处理多个媒体流,实现流畅的播放和录制。
  7. 游戏开发:在游戏开发中,线程通常用于同时处理游戏逻辑、图形渲染和用户输入,以提供流畅的游戏体验。

需要注意的是,虽然线程在很多情况下能够提高程序的性能和响应性,但多线程编程也带来了一些挑战,如数据同步与竞争条件。正确地处理线程同步和资源共享问题对于编写稳定和可靠的多线程应用程序至关重要。因此,在使用线程时,开发人员需要仔细考虑并采取适当的同步措施,以避免潜在的问题。

🎨 1.4,创建线程

有两种方式可以创建线程:

1,继承Thread 类并重写 run()方法;

2,实现Runnable接口;

1.4.1,继承 Thread类的方式

  1. 定义子类继承Thread类。
  2. 类中重写Thread类中的run方法。
  3. 创建Thread子类对象,即创建了线程对象。
  4. 调用线程对象start方法:启动线程,调用run方法。

案例:

启动一个线程,在线程中执行1-10000的偶数打印工作:

public class MyThread extends Thread {@Overridepublic void run() {for (int i = 1; i <= 10000; i++) {if (i % 2 == 0) {//Thread.currentThread().getName():得到线程的名字System.out.println(Thread.currentThread().getName() + "\t" + i);}}}
}

测试:

public class Test1 {public static void main(String[] args) {MyThread myThread1 = new MyThread();myThread1.start();MyThread myThread2 = new MyThread();myThread2.start();System.out.println(Thread.currentThread().getName() + "  main 线程 over");}
}
        JOptionPane.showMessageDialog(null, "是否确认向下执行...."); //主线程进入IO阻塞System.out.println("main over");
  • 如果子线程执行,进程不会停止。

1.4.2,实现Runanble接口:

  • 定义子类,实现Runnable接口。
  • 类中重写Runnable接口中的run方法。
  • 通过Thread类含参构造器创建线程对象。
  • 将Runnable接口的子类对象作为实际参数传递给Thread类的构造器中。
  • 调用Thread类的start方法:开启线程, 调用Runnable子类接口的run方法。
public class ThreadDemo {public static void main(String[] args) {//方式1:Thread子类,启动MyThread thread1 = new MyThread();thread1.start();//方式2:Runable方式(推荐的方式)//优势:可以实现多继承,比如继承BaseDao,然后再实现RunnableMyTask task = new MyTask();Thread thread2 = new Thread(task);thread2.start();//方式3:匿名内部类new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i <= 100; i++) {System.out.println(Thread.currentThread().getName() +  "\t" +  i);}}}).start();}}//方式1
class MyThread extends Thread {@Overridepublic void run() {for (int i = 0; i <= 100; i++) {System.out.println(Thread.currentThread().getName() +  "\t" +  i);}}
}//方式2
//优势:可以实现多继承,比如继承BaseDao,然后再实现Runnable
class MyTask implements Runnable {@Overridepublic void run() {for (int i = 0; i <= 100; i++) {System.out.println(Thread.currentThread().getName() +  "\t" +  i);}}
}

1.4.3,Thread 常见方法

  • 构造函数

    • Thread(): 创建新的Thread对象
    • Thread(String threadname): 创建线程并指定线程实例名
    • Thread(Runnable target): 指定创建线程的目标对象,它实现了Runnable接口中的run方法
    • Thread(Runnable target, String name): 创建新的Thread对象
  • void start(): 启动线程,并执行对象的run()方法

  • run(): 线程在被调度时执行的操作

  • String getName(): 返回线程的名称

  • **void setName(String name)😗*设置该线程名称

  • static Thread currentThread(): 返回当前线程。在Thread子类中就是this,通常用于主线程和Runnable实现类

  • static void yield(): 线程让步

    • 暂停当前正在执行的线程,把执行机会让给优先级相同或更高的线程
    • 若队列中没有同优先级的线程,忽略此方法
  • join() : 当某个程序执行流中调用其他线程的 join() 方法时, 调用线程将被阻塞,直到 join() 方法加入的 join 线程执行完为止

  • static void sleep(long millis): (指定时间:毫秒) 令当前活动线程在指定时间段内放弃对CPU控制,使其他线程有机会被执行,时间到后重排队。

  • stop(): 强制线程生命期结束,不推荐使用

  • boolean isAlive(): 返回boolean,判断线程是否还活着

1.4.4,sleep()方法

指定线程休眠的时间,单位毫秒,让出cpu时间片,其他线程可以抢占时间片

public class MyTask implements Runnable {@Overridepublic void run() {for (int i = 1; i <= 100; i++) {if (i % 2 == 0) {//Thread.currentThread().getName():得到线程的名字System.out.println(Thread.currentThread().getName() + "\t" + i);try {Thread.sleep(1000);Thread.yield();} catch (InterruptedException e) {throw new RuntimeException(e);}}}}
}

1.4.5,线程优先级

  • 线程的优先级等级

    • MAX_PRIORITY: 10
    • MIN _PRIORITY: 1
    • NORM_PRIORITY: 5
    public static void main(String[] args) {MyTask myTask = new MyTask();Thread thread1 = new Thread(myTask, "t1");thread1.setPriority(Thread.MIN_PRIORITY);thread1.start();Thread thread2 = new Thread(myTask, "t2");thread1.setPriority(Thread.MAX_PRIORITY);thread2.start();}

1.4.6,守护线程

  • 其他线程都执行结束,守护线程自动结束
  • 守护启动子线程,也是守护线程
  • 守护线程的语法thread.(*setDaemon(true)*设置守护线程
public class Test2 {public static void main(String[] args) {MyThread myThread1 = new MyThread();
//        myThread1.setDaemon(true);myThread1.start(); //守护线程, gc线程,jvm线程结束gc会自动结束JOptionPane.showMessageDialog(null, "是否确认向下执行...."); //主线程进入IO阻塞System.out.println("main over");}}class MyThread extends Thread {@Overridepublic void run() {while (true) {System.out.println("a");}}
}

1.4.7,线程合并

image-20230731101929769

案例:

public class Test1 {/*** CountDownLatch:可以实现相同的效果* @param args*/public static void main(String[] args) {Thread t1 = new Thread(new Runnable() {@Overridepublic void run() {for (int i = 1; i <= 100; i++) {System.out.println(Thread.currentThread().getName() + "\t" + i);try {Thread.sleep(10);} catch (InterruptedException e) {throw new RuntimeException(e);}}}});t1.start();try {t1.join();} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(Thread.currentThread().getName() +  "  main orver");}}

image-20230731102014846

1.4.8,线程退出

  • stop():不推荐,线程退出方式粗暴,不管线程正在执行的任务,直接退出,可能丢失数据。

    image-20230731102216532

    public class Test1 {public static void main(String[] args) {Thread t1 = new Thread(new MyTask());t1.start();Scanner in = new Scanner(System.in);System.out.println("输入1/0:0表示退出");int i = in.nextInt(); ///主线程进入IO阻塞if (i == 0) {t1.stop();}System.out.println("main over");}static class MyTask implements Runnable {@Overridepublic void run() {while (true) {try {Thread.sleep(100);} catch (InterruptedException e) {throw new RuntimeException(e);}}}}
    }
    
  • 中断信号interrupt

    image-20230731102257699

    • interrupt():发送中断信号(true)

      • 如果线程在阻塞状态,比如sleep(),join(),wait(),这时接收到中断信号会抛出一个异常InterruptException,同时中断信号清除(false)
      • 只是发送信号,不会对线程产生影响
    • **static interrupted():**得到中断信号(true),然后把中断信号设置成false

    • **isInterrupted():**得到中断信号,不会清除中断信号

    public class Test1 {public static void main(String[] args) {Thread t1 = new Thread(new MyTask());t1.start();JOptionPane.showMessageDialog(null, "是否确认向下执行...."); //主线程进入IO阻塞t1.interrupt(); //发送中断信号给t1System.out.println("main over");}static class MyTask implements Runnable {@Overridepublic void run() {while (true) {System.out.println("a");try {Thread.sleep(500000);} catch (InterruptedException e) {System.out.println("bbbbbbbbbbbbbbb");e.printStackTrace();Thread.currentThread().interrupt(); //再次发送中断信号,中断信号发给阻塞线程,抛出Interrupt异常,中断信号清除
    //                    throw new RuntimeException(e);}//得到中断信号,优雅的退出if (Thread.interrupted()) {break;}}}}
    }
    

📢 1.5,线程的生命周期

1.5.1,线程的调度与时间片

​ 由于 CPU 的计算频率非常高,每秒计算数十亿次,于是,可以将 CPU 的时间从毫秒的维度进行分段,每一小段叫做一个 CPU 时间片。不同的操作系统、不同的处理器,线程的 CPU 时间片长度都不同。假定操作系统的线程一个时间片的时间长度为 20 毫秒(比如 Windows XP),在一个 2GHz 的 CPU 上,那么一个时间片可以进行计算的次数是: 20 亿/(1000/20) =4 千万次,也就是说,一个时间片内的计算量是非常巨大的。 目前操作系统中主流的线程调度方式大都是:基于 CPU 时间片方式进行线程调度。线程只有得到 CPU 时间片,才能执行指令,处于执行状态;没有得到时间片的线程,处于就绪状态,等待系统分配下一个 CPU 时间片。由于时间片非常短,在各个线程之间快速地切换,表现出来特征是很多个线程在“同时执行”或者“并发执行”。线程的调度模型,目前主要分为两种调度模型:分时调度模型、抢占式调度模型。

(1)分时调度模型——系统平均分配 CPU 的时间片,所有线程轮流占用 CPU。分时调度模型在时间片调度的分配上,所有线程人人平等。

下图就是一个分时调度的简单例子:三个线程,轮流得到 CPU 时间片;一个线程执行时,另外两个线程处于就绪状态

image-20230731102854819

(2)抢占式调度模型——系统按照线程优先级分配 CPU 时间片。优先级高的线程,优先分配 CPU 时间片;如果所有的就绪线程的优先级相同,那么会随机选择一个;优先级高的线程获取的 CPU 时间片相对多一些。 由于目前大部分操作系统都是使用抢占式调度模型进行线程调度。 Java 的线程管理和调度是委托给了操作系统完成的,与之相对应, Java 的线程调度也是使用抢占式调度模型

1.5.2,线程状态

操作系统,线程的状态

image-20230731103051812

java的线程状态

得到java的线程状态

public Thread.State getState(); //返回当前线程的执行状态,一个枚举类型值

Thread.State是一个内部枚举类,定义了6个枚举常量,分别代表Java线程的6种抓过你太,具体如下:

public static enum State {NEW, //新建RUNNABLE, //可执行:包含操作系统的就绪、运行两种状态BLOCKED, //阻塞  -> 操作系统线程中的阻塞WAITING, //等待  -> 操作系统线程中的阻塞TIMED_WAITING, //计时等待 -> 操作系统线程中的阻塞TERMINATED; //终止}

Thread.State定义的6中状态中,有四种是比较常见的状态,他们是:NEW状态,RUNNABLE状态,TERMINATED状态,TIMED_WAITING状态。

接下来,将线程的6种状态以及各种状态的进入条件,做个总结:

  1. NEW状态:通过 new Thread(...)已经创建线程,但尚未调用start()启动线程,该线程处于NEW(新建)状态。虽然前面介绍了4种创建线程,但是其中的其他三种方式,本质上都是通过new Thread()创建的线程,仅仅是创建了不同的target执行目标示例(如Runnable实例)。

  2. RUNNABLE状态:Java 把就绪(Ready)和 执行(Running)两种状态合并为一种状态:可执行(RUNNABLE)状态(或者可运行状态)。调用了线程的start()实例方法后,线程就处于就绪状态了;此线程获取到CPU时间片后,开始执行run()方法种的业务代码,线程处于执行状态。

    image-20230731142105785

    • 就绪状态:就绪状态仅仅表示线程具备运行资格,如果没有被操作系统的调度程序挑选中,线程就永远是就绪状态;当前线程进入就绪状态的条件,大致包括以下几种:

      • 调用线程的start()方法,此线程进入就绪状态。
      • 当前线程的执行时间片用完。
      • 线程睡眠(sleep)操作结束。
      • 对其他线程合入(join)操作结束。
      • 等待用户输入结束。
      • 线程争抢到对象锁(Object Monitor)。
      • 当前线程调用了yield()方法,让出CPU执行权限。
    • 执行状态:线程调度程序从就绪状态的线程中选择一个线程,作为当前线程时线程所处的状态。这也是线程进入执行状态的唯一方式。

    • BLOCKED 状态: 处于阻塞(BLOCKED)状态的线程并不会占用CPU资源,以下情况会让线程进入阻塞状态:

      1. 线程等待获取锁 :等待获取一个锁,而该锁被其他线程持有,则该线程进入阻塞状态。当其他线程释放了该锁,并且线程调度器允许该线程持有该锁时,该线程退出阻塞状态。
      2. IO 阻塞:线程发起了一个阻塞式 IO 操作后,如果不具备 IO 操作的条件,线程会进入阻塞状态。 IO 包括磁盘 IO、 网络 IO 等。 IO 阻塞的一个简单例子:线程等待用户输入内容后继续执行。
    • WAITING 状态:处于 WAITING(无限期等待)状态的线程不会被分配 CPU 时间片,需要被其他线程显式地唤醒,才会进入就绪状态。线程调用以下 3 种方法,会让自己进入无限等待状态:

      1. Object.wait() 方法,对应的唤醒方式为: Object.notify() / Object.notifyAll()。
      2. Thread.join() 方法,对应的唤醒方式为:被合入的线程执行完毕。
      3. LockSupport.park() 方法,对应的唤醒方式为: LockSupport.unpark(Thread)。
    • TIMED_WAITING 状态:处于 TIMED_WAITING(限时等待)状态的线程不会被分配 CPU 时间片,如果指定时间之内没有被唤醒,限时等待的线程会被系统自动唤醒,进入就绪状态。以下 3 个方法会让线程进入限时等待状态:

      • Thread.sleep(time) 方法,对应的唤醒方式为: sleep 睡眠时间结束。
      • Object.wait(time) 方 法 , 对 应 的 唤 醒 方 式 为 : 调 用 Object.notify() /Object.notifyAll()去主动唤醒,或者限时结束。
      • LockSupport.parkNanos(time)/parkUntil(time) 方法,对应的唤醒方式为:线程调用配套的 LockSupport.unpark(Thread)方法结束,或者线程停止(park)时限结束。

      进入 BLOCKED 状态、 WAITING 状态、 TIMED_WAITING 状态的线程都会让出 CPU 的使用权;另外,等待或者阻塞状态的线程被唤醒后,进入 Ready 状态,需要重新获取时间片才能接着运行。

    • TERMINATED 状态:线程结束任务之后,将会正常进入 TERMINATED(死亡)状态;或者说在线程执行过程中发生了异常(而没有被处理),也会导致线程进入死亡状态。

1.5.3,多线程自增 i++ 和线程执行原理

4个线程自增一个堆(共享的)里的对象的值

public class Test {private int i =0;public void f1() {i++;}
}

i++的反编译结果

javap -c Test.class

image-20230801211556153

image-20230801211859089

线程产生时 ,为每个线程的一个虚拟机栈分配1M内存

-Xss128K:指定没有线程的栈大小是128K

自增类:

public class Plus {private int amount = 0;public void selfPlus() {amount ++;}public int getAmount() {return amount;}}

自增任务类

public class PlusTask implements Runnable {private Plus plus;public PlusTask() {}public PlusTask(Plus plus) {this.plus = plus;}@Overridepublic void run() {for (int i = 0; i < 100000000; i++) {plus.selfPlus();}}}

测试

    public static void main(String[] args) throws InterruptedException {Plus plus = new Plus();PlusTask plusTask = new PlusTask(plus);Thread t1 = new Thread(plusTask);Thread t2 = new Thread(plusTask);Thread t3 = new Thread(plusTask);Thread t4 = new Thread(plusTask);t1.start();t2.start();t3.start();t4.start();t1.join();t2.join();t3.join();t4.join();System.out.println("实际的值 = " + plus.getAmount());}

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

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

electron+vue+ts窗口间通信

文章目录 一. 目的二.逻辑分析三. 代码示例 "types/node": "^20.3.1","vitejs/plugin-vue": "^4.1.0","vueuse/electron": "^10.2.1","electron": "^25.2.0","electron-packager":…

Vue3和TypeScript_页面

1 在views下新建myView.view 2 在router文件夹里&#xff0c;配置路径&#xff0c;按需引入组件 3 浏览器通过路径访问页面

c语言——计算两个正整数的最大公倍数

//计算两个正整数的最大公倍数 //例如40和60的最大公约数为20. //计算两个正整数的最大公倍数 //例如40和60的最大公约数为20. #include<stdio.h> int main() {int a,b,temp,i;printf("Input a & b:");scanf("%d%d",&a,&b);if(a<b){…

【Java】Map<String,Object>中解析Object类型数据为数组格式(94)

背景&#xff1a; 前端&#xff1a;入参为字符串和数组类型&#xff1b;通过json字符串传给后台&#xff0c; 后台&#xff1a;后台通过工具解析为Map<String&#xff0c;Object>&#xff0c;然后需要解析出Map里面的数组值做操作&#xff1b; 需求&#xff1a; 入参&…

界面控件DevExpress BI Dashboard v23.1——支持全新的图标趋势指标

DevExpress BI Dashboard v23.1支持在Dashboard图表项中使用趋势指标&#xff0c;趋势指标有助于传达一段时间内的数据趋势——允许用户发现模式并更有效地分析复杂的数据集。 使用DevExpress Analytics Dashboard&#xff0c;再选择合适的UI元素&#xff08;图表、数据透视表…

JavaEE初阶之文件操作 —— IO

目录 一、认识文件 1.1认识文件 1.2树型结构组织 和 目录 1.3文件路径(Path) 1.4其他知识 二、Java 中操作文件 2.1File 概述 2.2代码示例 三、文件内容的读写 —— 数据流 3.1InputStream 概述 ​3.2FileInputStream 概述 3.3代码示例 3.4利用 Scanner 进行字…

ChatGPT安全技术

前言 近期&#xff0c;Twitter 博主 lauriewired 声称他发现了一种新的 ChatGPT"越狱"技术&#xff0c;可以绕过 OpenAI 的审查过滤系统&#xff0c;让 ChatGPT 干坏事&#xff0c;如生成勒索软件、键盘记录器等恶意软件。 他利用了人脑的一种"Typoglycemia&q…

IO(JavaEE初阶系列8)

目录 前言&#xff1a; 1.文件 1.1认识文件 1.2结构和目录 1.3文件路径 1.4文本文件vs二进制文件 2.文件系统的操作 2.1Java中操作文件 2.2File概述 2.2.1构造File对象 2.2.2File中的一些方法 3.文件内容的操作 3.1字节流 3.1.1InPutStream的使用方法 3.1.2OutPu…

给你一个小技巧,解放办公室管理!

电力的稳定供应对于现代社会中的办公室和企业来说至关重要。为了应对这些潜在的问题&#xff0c;许多办公室和企业都采用了不间断电源&#xff08;UPS&#xff09;系统来提供电力备份。UPS可以保持关键设备的运行&#xff0c;确保生产和业务不受干扰。 然而&#xff0c;仅仅安装…

【微服务】springboot整合redis哨兵集群使用详解

目录 一、前言 二、环境准备 三、安装redis 3.1 前置准备 3.1.1 下载安装包 3.1.2 准备依赖环境 3.1.3 上传并解压包 3.2 执行安装 四、搭建redis主从集群 4.1 环境准备 4.2 搭建过程 4.2.1 创建实例文件目录 4.2.2 修改redis.conf配置文件 4.2.3 拷贝配置文件 4…

小C说历史(人物介绍第一篇):传奇人物Linus Torvalds 缔造Linux和Git

传奇人物Linus Torvalds 缔造Linux和Git Linus Torvalds&#xff0c;1969年12月28日出生于芬兰的赫尔辛基&#xff0c;Linux核心的创作者。当Linus十岁时&#xff0c;他的祖父&#xff0c;赫尔辛基大学的一位统计教授&#xff0c;购买了一台Commodore VIC-20计算机。Linus帮助他…

【波浪动态特效】基于jquery实现页面底部波浪动画效果(附完整源码下载)

文章目录 写在前面涉及知识点实现效果1、搭建页面1.1、创建两个片区1.2、创建波浪区域1.3、静态页面源码 2、JS实现波浪效果2.1 动画原理2.2 动画源码 3、源码分享3.1 百度网盘3.2 123云盘3.3 邮箱留言 总结 写在前面 想必搭建过企业官网的大多数对这个效果不陌生吧&#xff0…

vue中显示在页面顶部的进度条插件——NProgress

我们在一些网站中经常见到导航栏上方的进度条显示&#xff0c;大家仔细观察&#xff0c;其实csnd中也有类似的效果&#xff0c;如下图显示效果&#xff0c;我们现在就来一起看看这个功能需求是怎么实现的。 一、功能需求 首先&#xff0c;实现这个功能其实不难&#xff0c;说实…

C# Microsoft消息队列服务器的使用 MSMQ

先安装消息队列服务器 private static readonly string path ".\\Private$\\myQueue";private void Create(){if (!MessageQueue.Exists(path)){MessageQueue.Create(path);}}private void Send(){Stopwatch stopwatch new Stopwatch();stopwatch.Start();Message…

动画制作选择Blender还是Maya

Blender和Maya是两种最广泛使用的 3D 建模和动画应用程序。许多经验丰富的用户表示&#xff0c;Blender 在雕刻工具方面远远领先于 Maya&#xff0c;并且在 3D 建模方面达到了相同的质量水平。对于刚接触动画行业的人来说&#xff0c;您可能会问“我应该使用 Blender 还是 Maya…

复习之vsftp服务

一、vsftp服务简介 文件传输协议&#xff08;File Transfer Protocol&#xff0c;FTP&#xff09;是用于在网络上进行文件传输的一套标准协议&#xff0c;它工作在 OSI 模型的第七层 即应用层&#xff0c; 使用 TCP 传输而不是 UDP&#xff0c; 客户在和服务器建立连接前要经过…

mac电脑访问windows共享文件夹连接不上(设置445端口)

前提&#xff1a;首先需要保证mac和windows都在同一局域网内&#xff0c;如果不在肯定是连不上的&#xff0c;就不用往下看了。 事情是这样的&#xff0c;公司入职发了mac电脑&#xff0c;但是我是window重度用户&#xff0c;在折腾mac的过程中&#xff0c;有许多文件需要从wi…

运维作业4

一.简述静态网页和动态网页的区别。 静态页面资源特征 1. 处理文件类型&#xff1a;如.html、jpg、.gif、.mp4、.swf、.avi、.wmv、.flv等 2. 地址中不含有问号"&#xff1f;"或&等特殊符号。 3. 保存在网站服务器文件系统上的&#xff0c;是实实在在保存在服务器…

【有趣的】关于Map的一些小测试

Map在代码中用到得非常多&#xff0c;它是无序的、key-value结构的&#xff0c;其读取会非常快。 今天看了个小文章Map判空 、空字符串、空key值等各种判断方法&#xff0c;你都掌握了吗&#xff1f;便自己也玩一下。 一、判空 因为对象已经new出来了&#xff0c;所以map指向的…

Zabbix报警机制、配置钉钉机器人、自动发现、主动监控概述、配置主动监控、zabbix拓扑图、nginx监控实例

day02 day02配置告警用户数超过50&#xff0c;发送告警邮件实施验证告警配置配置钉钉机器人告警创建钉钉机器人编写脚本并测试添加报警媒介类型为用户添加报警媒介创建触发器创建动作验证自动发现配置自动发现主动监控配置web2使用主动监控修改配置文件&#xff0c;只使用主动…