多线程与高并发——并发编程(1)

news2025/1/10 0:06:57

文章目录

  • 并发编程
  • 一、线程的基本概念
    • 1 基础概念
      • 1.1 进程和线程
      • 1.2 多线程
      • 1.3 串行、并行、并发
      • 1.4 同步异步、阻塞非阻塞
    • 2 线程的创建
      • 2.1 继承Thread类,重写run方法
      • 2.2 实现Runnable接口,实现run方法
      • 2.3 实现Callable接口,实现call方法,配合FutureTask
      • 2.4 基于线程池构建线程
    • 3 线程的使用
      • 3.1 线程的使用
      • 3.2 线程常用的方法
        • 3.2.1 获取当前线程
        • 3.2.2 线程的名字
        • 3.2.3 线程的优先级
        • 3.2.4 线程的让步
        • 3.2.5 线程的休眠
        • 3.2.6 线程的抢占
        • 3.2.7 线程守护
        • 3.2.8 线程的等待和唤醒
      • 3.3 线程的结束方式
        • 3.3.1 stop 方法(不用)
        • 3.3.2 使用共享变量(很少使用)
        • 3.3.3 interrupt 方法

并发编程

一、线程的基本概念

1 基础概念

1.1 进程和线程

什么是进程?

  • 进程是指运行中的程序。比如我们使用的钉钉、浏览器,需要启动这个程序,操作系统会给这个程序分配一定的资源(占用内存资源)。

什么是线程?

  • 线程是CPU调度的基本单位,每个线程执行的都是某一个进程的代码的某个片段。

举个例子:人和房子

比如,现在有一个 100 平米的房子,这个房子就可以看做是一个进程。房子里有人,人就可以看做是一个线程。人在房子里做一些事,比如:吃饭、学习、睡觉,这个就好像现场在执行某个功能的代码。

  • 所谓进程就是线程的容器,需要线程利用进程的一些资源,处理一个代码/指令,最终实现进程所预期的结果。

进程和线程的区别?

  • 本质不同:进程是操作系统分配的资源,而线程是CPU调度的基本单位。
  • 资源不同:统一个进程下的线程共享进程的一些资源,线程同时拥有自身的独立存储空间,进程之间的资源通常是独立。
  • 数量不同:进程就是一个进程,而线程是依附于某个进程的,而且一个进程中至少有一个或多个线程。
  • 开销不同:毕竟进程和线程不是一个级别的内容,线程的创建和终止时间是比较短的。而且线程之间的切换比进程之间的切换速度要快很多。而且进程之间的通讯很麻烦,一般要借助内核才可以实现;而线程之间通信,相当方便。

1.2 多线程

什么是多线程?

  • 多线程是指,单个进程中同时运行多个线程。
  • 多线程的目的就是为了提高CPU的利用率,可以通过避免一些网络IO或磁盘IO等需要等待的操作,让CPU去调度其他线程。这样可以大幅度提升程序的效率,提高用户的体验。

比如:Tomcat就可以做并行处理,提升处理的效率,而不是一个一个排队。

再比如:要处理一个网络等待操作,开启一个线程去处理需要网络等待的任务,让当前业务线程可以继续往下执行逻辑,效率可以得到大幅度提升。

多线程的局限性?

  • 如果线程数量特别多,CPU在切换上下文时,会额外造成很大的消耗。
  • 任务的拆分需要依赖业务场景,有一些异构化的任务,很难对任务拆分,并不是多线程处理就更好。
  • 线程安全问题:虽然多线程带来了一定的性能提升,但是在做一个操作时,多线程如果操作临界资源,可能会发生一些数据不一致的问题,甚至涉及到锁的操作时,会造成死锁的问题。

1.3 串行、并行、并发

什么是串行?

  • 串行就是一个一个排队,第一个做完,第二个才上。

什么是并行?

  • 并行就是同时处理(一起上!!)

什么是并发?

  • 这里的并发并不是三高中的高并发问题,这里是指多线程的并发概念(CPU调度线程的概念)。CPU在极短的时间内,反复切换执行不同的线程,看似好像是并行,但只是CPU的高速切换。
  • 并行囊括并发,并行就是多核CPU同时调度多个线程,是真正的多个线程同时执行。单核CPU无法实现并行效果,单核CPU是并发。

1.4 同步异步、阻塞非阻塞

同步与异步?

  • 执行完某个功能后,被调用者是否会主动反馈信息。

阻塞与非阻塞?

  • 执行完某个功能后,调用者是否需要一直等待结果的反馈。

同步阻塞:比如用锅烧水,水开后不会主动通知你;烧水开始执行后,需要一直等待水烧开。

同步非阻塞:比如用锅烧水,水开后不会主动通知你;烧水开始执行后,不需要一直等待水烧开,可以去执行一下其他的操作,但是需要时不时查看水开了没。

异步阻塞:比如用锅烧水,水开后会主动通知你水烧开了;烧水开始执行后,需要一直等待水烧开。

异步非阻塞:比如用锅烧水,水开后会主动通知你水烧开了;烧水开始执行后,不需要一直等待水烧开,可以去执行一下其他的操作。这个效果是最好的,平时开发时,提升效率最好的方式就是采用异步非阻塞的方式处理一些多线程的任务。

2 线程的创建

线程的创建分为三种方式:

2.1 继承Thread类,重写run方法

  • 启动线程时,调用 start() 方法,这样会创建一个新的线程,并执行线程的任务。
  • 如果直接调用 run() 方法,这样仅仅只会让当前执行 run 方法中的业务逻辑。
public class MyTest {
    public static void main(String[] args) {
        MyJob t1 = new MyJob();
        t1.start();
        for (int i = 0; i < 100; i++) {
            System.out.println("main:" + i);
        }
    }
}
class MyJob extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("MyJob:" + i);
        }
    }
}

2.2 实现Runnable接口,实现run方法

public class MyTest {
    public static void main(String[] args) {
        MyRunnable runnable = new MyRunnable();
        Thread t1 = new Thread(runnable);
        t1.start();
        for (int i = 0; i < 1000; i++) {
            System.out.println("main:" + i);
        }
    }
}
class MyRunnable implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("MyRunnable:" + i);
        }
    }
}

最常用的方式:

// 匿名内部类方式:
Thread t1 = new Thread(new Runnable() {
    @Override
    public void run() {
        for (int i = 0; i < 1000; i++) {
            System.out.println("匿名内部类:" + i);
        }
    }
});
// Lambda 方式:
Thread t2 = new Thread(() -> {
    for (int i = 0; i < 1000; i++) {
        System.out.println("Lambda:" + i);
    }
});

2.3 实现Callable接口,实现call方法,配合FutureTask

  • Callable 一般用于有返回值的非阻塞的执行方法——同步非阻塞
public class MyTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 1. 创建 MyCallable
        MyCallable callable = new MyCallable();
        // 2. 创建 FutureTask,传入Callable
        FutureTask task = new FutureTask<>(callable);
        // 3. 创建 Thread 线程
        Thread t1 = new Thread(task);
        t1.start();
        // 4. 启动线程
        t1.start();
        // 5. 做一些操作...
        // 6. 获取结果
        Object count = task.get();
        System.out.println("总和为:" + count);
    }
}
class MyCallable implements Callable {
    @Override
    public Object call() throws Exception {
        int count = 0;
        for (int i = 0; i < 100; i++) {
            count += i;
        }
        return count;
    }
}

2.4 基于线程池构建线程

  • 底层其实是一种,实现 Runnable。

3 线程的使用

3.1 线程的使用

网上对线程状态的描述有很多,有说 5 种的、6中的、7种的,都可以接受。

  • 5 种状态:一般是针对传统的线程状态来说(操作系统层面)

在这里插入图片描述

  • Java中给线程定义了 6 种状态:

在这里插入图片描述

  • NEW:Thread 对象被创建出来了,但是还没有执行start方法。
  • RUNNABLE:Thread 对象调用了 start 方法,就为 RUNNABLE 状态(CPU调度/没有调度)。
  • BLOCKED、WAITING、TIMED_WAITING:都可以理解为是阻塞、等待状态,因为处于这三种状态下,CPU都不会调度当前线程。
    • BLOCKED:是 synchronized 没有拿到同步锁,被阻塞的情况;
    • WAITING:调用 wait 方法就会处于 WAITING 状态,需要被手动唤醒;
    • TIMED_WAITING:调用 sleep 方法或者 join 方法,会被自动唤醒,无需手动唤醒。
  • TERMINATED:run方法执行完毕,线程生命周期到头了。

代码演示

  • NEW:
public static void main(String[] args) {
    Thread t1 = new Thread(() -> {});
    System.out.println(t1.getState());
}
  • RUNNABLE:
public static void main(String[] args) throws InterruptedException {
    Thread t1 = new Thread(() -> {
        while (true) {

        }
    });
    t1.start();
    Thread.sleep(500);
    System.out.println(t1.getState());
}
  • BLOCKED:
public static void main(String[] args) throws InterruptedException {
    Object obj = new Object();
    Thread t1 = new Thread(() -> {
        // t1 线程拿不到锁资源,导致变为 BLOCKED状态
        synchronized (obj) {

        }
    });
    // main线程拿到obj的锁资源
    synchronized (obj) {
        t1.start();
        Thread.sleep(500);
        System.out.println(t1.getState());
    }
}
  • WAITING:
public static void main(String[] args) throws InterruptedException {
    Object obj = new Object();
    Thread t1 = new Thread(() -> {
        synchronized (obj) {
            try {
                obj.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    t1.start();
    Thread.sleep(500);
    System.out.println(t1.getState());
}
  • TIMED_WAITING:
public static void main(String[] args) throws InterruptedException {
    Thread t1 = new Thread(() -> {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
    t1.start();
    Thread.sleep(500);
    System.out.println(t1.getState());
}
  • TERMINATED:
public static void main(String[] args) throws InterruptedException {
    Thread t1 = new Thread(() -> {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
    t1.start();
    Thread.sleep(1000);
    System.out.println(t1.getState());
}

3.2 线程常用的方法

3.2.1 获取当前线程

  • Thread 的静态方法,获取当前线程对象
public static void main(String[] args) throws InterruptedException {
    Thread currentThread = Thread.currentThread();
    System.out.println(currentThread);
    // "Thread[" + getName() + "," + getPriority() + "," + group.getName() + "]";
    // Thread[main,5,main]
}

3.2.2 线程的名字

  • 在构建 Thread 对象完毕后,一定要设置一个有意义的名称,方便后期排查错误
public static void main(String[] args) {
    Thread t1 = new Thread(() -> {
        System.out.println(Thread.currentThread().getName());
    });
    t1.setName("模块-功能-计数器");
    t1.start();
}

3.2.3 线程的优先级

  • 其实就是 CPU 调度线程的优先级,Java 中给线程设置的优先级有 10 个级别,从 1 ~ 10 任取一个整数,如果超出这个范围,会报出参数异常的错误。
public static void main(String[] args) {
    Thread t1 = new Thread(() -> {
        for (int i = 0; i < 1000; i++) {
            System.out.println("t1: " + i);
        }
    });
    Thread t2 = new Thread(() -> {
        for (int i = 0; i < 1000; i++) {
            System.out.println("t2:" + i);
        }
    });
    t1.setPriority(1);
    t2.setPriority(10);
    t2.start();
    t1.start();
}

3.2.4 线程的让步

  • 可以通过 Thread 的静态方法 yield,让当前线程从运行状态转变为就绪状态。
public static void main(String[] args) {
    Thread t1 = new Thread(() -> {
        for (int i = 0; i < 100; i++) {
            if (i == 50) {
                Thread.yield();
            }
            System.out.println("t1:" + i);
        }
    });
    Thread t2 = new Thread(() -> {
        for (int i = 0; i < 100; i++) {
            System.out.println("t2:" + i);
        }
    });
    t2.start();
    t1.start();
}

3.2.5 线程的休眠

  • Thread 的静态方法,让线程从运行状态变为等待状态。
  • sleep 有两个方法重载:
    • 第一个就是 native 修饰的,让线程转为等待状态的效果;
    • 第二个是可以传入毫秒和一个纳秒的方法(如果纳秒值大于等于 0.5ms,就给休眠的毫秒值+1;如果传入的毫秒值为0,纳秒值不为0,就休眠1ms)
  • sleep会抛出一个 InterruptedException
public static void main(String[] args) throws InterruptedException {
    System.out.println(System.currentTimeMillis());
    Thread.sleep(1000);
    System.out.println(System.currentTimeMillis());
}

3.2.6 线程的抢占

  • Thread 的非静态方法 join,需要再某一个线程下去调用这个方法。
  • 如果main线程中调用了 t1.join(),那么 main 线程会进入到等待状态,需要等待 t1 线程全部执行完毕,再恢复到就绪状态等待 CPU 调度。
  • 如果main线程中调用了 t1.join(2000),那么 main 线程会进入到等待状态,需要等待 t1 执行 2s 后,恢复到就绪状态等待 CPU 调度。如果在等待期间,t1 已经结束了,那么 main 线程自动变为就绪状态等待CPU调度。
public static void main(String[] args) {
    Thread t1 = new Thread(() -> {
        for (int i = 0; i < 10; i++) {
            System.out.println("t1:" + i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    t1.start();
    for (int i = 0; i < 10; i++) {
        System.out.println("main:" + i);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (i == 1) {
            try {
                t1.join(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

3.2.7 线程守护

  • 默认情况下,线程都是非守护线程。JVM 会在程序没有非守护线程时,结束掉当前 JVM。
  • 主线程默认是非守护线程,如果主线程执行结束,需要查看当前 JVM 内是否还有非守护线程,如果没有 JVM 会直接停止。
public static void main(String[] args) {
    Thread t1 = new Thread(() -> {
        for (int i = 0; i < 10; i++) {
            System.out.println("t1:" + i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });
    t1.setDaemon(true);
    t1.start();
}

3.2.8 线程的等待和唤醒

  • 可以让获取 synchronized 锁资源的线程,通过 wait 方法进入到锁的等待池,并且会释放锁资源。
  • 可以让获取 synchronized 锁资源的线程,通过 notify 或者 notifyAll 方法,将等待池中的线程唤醒,添加到锁池中。
  • notify 会随机的唤醒等待池中的一个线程到锁池中,notifyAll 会将等待池中的全部线程都唤醒,并添加到锁池中。
  • 在调用 wait 方法和notify、notifyAll 方法时,必须在 synchronized 修饰的代码块或者方法内部才可以,因为要操作基于某个对象的锁的信息维护。
public static void main(String[] args) throws InterruptedException {
   Thread t1 = new Thread(() -> {
       sync();
   }, "t1");
   Thread t2 = new Thread(() -> {
       sync();
   }, "t2");
   t1.start();
   t2.start();
   Thread.sleep(12000);
   synchronized (MyTest.class) {
       MyTest.class.notifyAll();
   }
}

private static synchronized void sync() {
    try {
        for (int i = 0; i < 10; i++) {
            if (i == 5) {
                MyTest.class.wait();
            }
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName());
        }
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

3.3 线程的结束方式

  • 线程结束的方式很多,最常用的是让线程的 run 方法结束,无论是 return 结束,还是抛异常结束,都可以。

3.3.1 stop 方法(不用)

  • 强制让线程结束,无论你在干嘛,不推荐使用这种方式,但是,它确实可以把线程干掉。
public static void main(String[] args) throws InterruptedException {
    Thread t1 = new Thread(() -> {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
    t1.start();
    Thread.sleep(500);
    t1.stop();
    System.out.println(t1.getState());
}

3.3.2 使用共享变量(很少使用)

  • 这种方式用的也不多,有的线程可能会通过死循环来保证一直运行,这个时候可以通过修改共享变量来破坏死循环,让线程退出循环,结束 run 方法。
static volatile boolean flag = true;

public static void main(String[] args) throws InterruptedException {
    Thread t1 = new Thread(() -> {
        while (flag) {
            // 处理任务
        }
        System.out.println("任务结束");
    });
    t1.start();
    Thread.sleep(500);
    flag = false;
}

3.3.3 interrupt 方法

  • 共享变量方式
public static void main(String[] args) throws InterruptedException {
    // 线程默认情况下,interrupt标记位:false
    System.out.println(Thread.currentThread().isInterrupted());
    // 执行interrupt之后,再次查看打断信息
    Thread.currentThread().interrupt();
    // interrupt标记为:true
    System.out.println(Thread.currentThread().isInterrupted());
    // 返回当前下线程,并归位为 false,interrupt标记为:true
    // 已经归位了
    System.out.println(Thread.currentThread().isInterrupted());

    // ====
    Thread t1 = new Thread(() -> {
        while (!Thread.currentThread().isInterrupted()) {
            // 处理业务
        }
        System.out.println("t1结束");
    });
    t1.start();
    Thread.sleep(500);
    t1.interrupt();
}
  • 通过打断 WAITING 或者 TIMED_WAITING 状态的线程,从而抛出异常自行处理,这种停止线程的方式是最常用的一种,在框架和 JUC 中也是最常见的。
public static void main(String[] args) throws InterruptedException {
    Thread t1 = new Thread(() -> {
        while (true) {
            // 获取任务
            // 拿到任务,执行任务
            // 没有任务了,让线程休眠
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("基于打断形式结束当前线程");
                return;
            }
        }
    });
    t1.start();
    Thread.sleep(500);
    t1.interrupt();
}

wait 和 sleep 的区别?

  • 单词不一样;
  • sleep 属于 Thread 类中的静态方法,wait 属于 Object 类的方法;
  • sleep 数据 TIMED_WAITING,自动被唤醒,wait 属于 WAITING,需要手动唤醒;
  • sleep 方法在持有锁时,执行后不会释放锁资源,wait 在执行后会释放锁资源;
  • sleep 可以在持有锁或者不持有锁时执行,wait 方法必须在持有锁时才可以执行。

wait 方法会将持有锁的线程从owner扔到WaitSet集合中,这个操作是在修改ObjectMonitor对象,如果没有持有synchronized锁的话,是无法操作ObjectMonitor对象的。

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

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

相关文章

Spring Boot+Atomikos进行多数据源的分布式事务管理详解和实例

文章目录 0.前言1.参考文档2.基础介绍3.步骤1. 添加依赖到你的pom.xml文件:2. 配置数据源及其对应的JPA实体管理器和事务管理器:3. Spring BootMyBatis集成Atomikos4. 在application.properties文件中配置数据源和JPA属性&#xff1a; 4.使用示例5.底层原理 0.前言 背景&#x…

漏洞复现 || SXF应用交付系统RCE(0Day)

漏洞描述 SXF应用交付管理系统login存在远程命令执行漏洞&#xff0c;攻击者通过漏洞可以获取服务器权限&#xff0c;执行任意命令。 免责声明 技术文章仅供参考&#xff0c;任何个人和组织使用网络应当遵守宪法法律&#xff0c;遵守公共秩序&#xff0c;尊重社会公德&#…

【Linux】ctime、mtime、atime

/etc/fstab中的noatime noatimedir 挂载选项linux下文件的ctime、mtime、atime一、/etc/fstab /etc/fstab是用来存放文件系统的静态信息的文件。 系统开机时会主动读取/etc/fstab这个文件中的内容,根据文件里面的配置挂载磁盘。这样我们只需要将磁盘的挂载信息写入这个文件中…

libevent源码学习3---事件event

libevent源码学习3—事件event libevent 的基本操作单元是事件。每个事件代表一组条件的集合, 这些条件包括: 文件描述符已经就绪, 可以读取或者写入文件描述符变为就绪状态,可以读取或者写入(仅对于边沿触发 IO)超时事件发生某信号用户触发事件 所有事件具有相似的生命周期。…

C++ string 类

文章目录 引用头文件初始化赋值1. 空串2. 拷贝复制3. 直接初始化赋值4. 单个字符初始化 遍历 string 类1. 下标索引遍历2. 迭代器遍历3. 使用 range for 循环遍历字符串&#xff08;需要 C11 或更新的版本&#xff09; string 常用方法判断字符串是否为空串获取字符串中字符个数…

Mysql简短又易懂

MySql 连接池:的两个参数 最大连接数&#xff1a;可以同时发起的最大连接数 单次最大数据报文&#xff1a;接受数据报文的最大长度 数据库如何存储数据 存储引擎&#xff1a; InnoDB:通过执行器对内存和磁盘的数据进行写入和读出 优化SQL语句innoDB会把需要写入或者更新的数…

FFI绕过disable_functions

文章目录 FFI绕过disable_functions[RCTF 2019]NextphpPHP7.4 FFI参考 FFI绕过disable_functions [RCTF 2019]Nextphp 首先来看这道题目 index.php <?php if (isset($_GET[a])) {eval($_GET[a]); } else {show_source(__FILE__); }查看一下phpinfo 发现过滤了很多函数&…

如何高效管理生产物料?

导 读 ( 文/ 2358 ) 所谓巧妇难为无米之炊&#xff0c;物料是生产过程的必需品&#xff0c;确保物料及时到料尤为关键&#xff0c;但堆积过多的物料库存将导致不必要的成本挤压。做好生产物料管理是门技术活&#xff0c;它的目标是确保所需的物料按时提供给生产线&#xff0c;以…

嘉立创EDA设计学习笔记1:开发环境下载与熟悉

今日开始尝试自己学习绘制PCB开发板&#xff0c;使得以后的学习小项目制作的成品不再受外形大小与他人布线的限制&#xff0c;用的软件是嘉立创EDA设计软件&#xff0c;这样直接布线检查与下单&#xff0c;十分方便。 嘉立创EDA设计软件下载&#xff1a; 首先上网址&#xff0…

【IMX6ULL驱动开发学习】09.Linux之I2C框架简介和驱动程序模板

参考&#xff1a;Linux之I2C驱动_linux i2c驱动_风间琉璃•的博客-CSDN博客​​​​​​ 目录 一、I2C驱动框架简介 1.1 I2C总线驱动 1.2 I2C设备驱动 二、I2C总线-设备-驱动模型 2.1 i2c_driver 2.2 i2c_client 2.3 I2C 设备数据收发和处理 三、Linux I2C驱动程序模板…

redis常用五种数据类型详解

目录 前言&#xff1a; string 相关命令 内部编码 应用场景 hash 相关命令 内部编码 应用场景 list 相关命令 内部编码 应用场景 set 相关命令 内部编码 应用场景 Zset 相关命令 内部编码 应用场景 渐进式遍历 前言&#xff1a; redis有多种数据类型&…

Java实现一个简单的图书管理系统(内有源码)

简介 哈喽哈喽大家好啊&#xff0c;之前作者也是讲了Java不少的知识点了&#xff0c;为了巩固之前的知识点再为了让我们深入Java面向对象这一基本特性&#xff0c;就让我们完成一个图书管理系统的小项目吧。 项目简介&#xff1a;通过管理员和普通用户的两种操作界面&#xff0…

【网络安全】防火墙知识点全面图解(三)

本系列文章包含&#xff1a; 【网络安全】防火墙知识点全面图解&#xff08;一&#xff09;【网络安全】防火墙知识点全面图解&#xff08;二&#xff09;【网络安全】防火墙知识点全面图解&#xff08;三&#xff09; 防火墙知识点全面图解&#xff08;三&#xff09; 39、什…

生成式人工智能的潜在有害影响与未来之路(二)

利润高于隐私&#xff1a;不透明数据收集增加 背景和风险 生成型人工智能工具建立在各种大型、复杂的机器学习模型之上&#xff0c;这些模型需要大量的训练数据才能发挥作用。对于像ChatGPT这样的工具&#xff0c;数据包括从互联网上抓取的文本。对于像Lensa或Stable Diffusi…

C语言练习1(巩固提升)

C语言练习1 选择题 前言 “人生在勤&#xff0c;勤则不匮。”幸福不会从天降&#xff0c;美好生活靠劳动创造。全面建成小康社会的奋斗目标&#xff0c;为广大劳动群众指明了光明的未来&#xff1b;全面建成小康社会的历史任务&#xff0c;为广大劳动群众赋予了光荣的使命&…

让你对es有一个初步的了解

首先es在海量数据的搜索能力非常好&#xff0c;es你可以把他看成一个搜索引擎数据库&#xff0c;他是个非关系型数据库。他的语法有很大的不同&#xff0c;好像都是json风格的。还有一点需要说的就是es 的数据是存在硬盘上的&#xff0c; 我们先来看一下mysql和es的区别吧。一…

边写代码边学习之Bidirectional LSTM

1. 什么是Bidirectional LSTM 双向 LSTM (BiLSTM) 是一种主要用于自然语言处理的循环神经网络。 与标准 LSTM 不同&#xff0c;输入是双向流动的&#xff0c;并且它能够利用双方的信息。 它也是一个强大的工具&#xff0c;可以在序列的两个方向上对单词和短语之间的顺序依赖…

4H-SiC UMOSFET 结构中带有 p+-polySi/SiC 被屏蔽区的模拟研究

标题&#xff1a;Simulation Study of 4H-SiC UMOSFET Structure With p -polySi/SiC Shielded Region 摘要 在这篇论文中&#xff0c;我们提出了一种改进效率的4H-SiC U型沟槽栅MOSFET&#xff08;UMOSFET&#xff09;结构。所提出的器件结构利用ppolySi/SiC被屏蔽区来降低导…

学习Linux的注意事项(使用经验;目录作用;服务器注意事项)

本篇分享学习Linux过程中的一些经验 文章目录 1. Linux系统的使用经验2. Linux各目录的作用3. 服务器注意事项 1. Linux系统的使用经验 Linux严格区分大小写Linux中所有内容以文件形式保存&#xff0c;包括硬件&#xff0c;Linux是以管理文件的方式操作硬件 硬盘文件是/dev/s…

mybatis概述及搭建

目录 1.概述 2.mybatis搭建 1.创建一个maven项目&#xff0c;添加mybatis、mysql所依赖的jar 2.创建一个数据库表&#xff0c;及对应的java类 3.创建一个mybatis的核心配置文件&#xff0c;配置数据库连接信息&#xff0c;配置sql映射文件 4.创建sql映射文件&#xff0c;…