JUC八股(持续更新中)

news2024/9/9 6:47:21

写在前面:本文为个人八股复习所用,整合了其他平台的答案加自己的理解,希望能对大家的八股复习有所帮助,答案可能存在出入,请大家理性食用~~

1. 进程和线程的区别

进程

进程是操作系统资源分配的基本单位,是程序的一次执行过程,进程之间是相互独立的,各自有各自的内存空间,它由操作系统进行调度。

线程

线程是CPU执行调度的基本单位,一个进程在其执行的过程中会产生多个线程,与进程不同的是同类的多个线程共享进程的堆和方法区资源,但每个线程有自己的程序计数器虚拟机栈本地方法栈,所以系统在产生一个线程,或是在各个线程之间做切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。

下面来思考这样一个问题:为什么程序计数器虚拟机栈本地方法栈线程私有的呢?为什么方法区线程共享的呢?

1.1. 程序计数器为什么是私有的?

程序计数器主要有下面两个作用:

  1. 字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。
  2. 在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。

需要注意的是,如果执行的是 native 方法,那么程序计数器记录的是 undefined 地址,只有执行的是 Java 代码时程序计数器记录的才是下一条指令的地址。

所以,程序计数器私有主要是为了线程切换后能恢复到正确的执行位置

1.2. 虚拟机栈和本地方法栈为什么是私有的?

  1. 虚拟机栈: 每个 Java 方法在执行之前会创建一个栈帧用于存储局部变量表、操作数栈、常量池引用等信息。从方法调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。
  2. 本地方法栈: 和虚拟机栈所发挥的作用非常相似,区别是:虚拟机栈为虚拟机执行 Java 方法 (也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。 在 HotSpot 虚拟机中和 Java 虚拟机栈合二为一。

所以,为了保证线程中的局部变量不被别的线程访问到,虚拟机栈和本地方法栈是线程私有的

1.3. 一句话简单了解堆和方法区

堆和方法区是所有线程共享的资源,其中是进程中最大的一块内存,主要用于存放新创建的对象 (几乎所有对象都在这里分配内存)方法区主要用于存放已被加载的类信息、常量、静态变量、即时编译器编译后的代码等数据

2. 线程的生命周期和状态

Java 线程在运行的生命周期中的指定时刻只可能处于下面 6 种不同状态的其中一个状态:

  • 新建(New):线程对象被创建出来,但还未调用start()启动的状态。
  • 就绪(Runnable):线程已经被启动,等待系统分配资源来运行。处于就绪状态的线程可能正在等待CPU时间片或等待某些条件满足。使用时间片轮转、优先级队列等调度算法来运行线程。
  • 运行(Running):线程获得CPU资源正在执行任务
  • 阻塞(Blocked):线程在等待某个锁或其他条件,如等待IO完成。
    • 比如,线程A与线程B代码中使用同一锁,如果线程A获取到锁,线程A进入到Runnable状态,那么线程B就进入到Blocked锁阻塞状态。
  • 等待(Waiting):线程等待其他线程通知调度器一个特定条件,通常是由于调用了Object.wait()Thread.join()或者LockSupport.park() 等方法。
  • 终止(Terminated):线程执行完毕或者因为异常退出了 run() 方法。

3. 切换线程状态的方法

线程的状态是由JVM根据线程的行为和调度来管理和切换的,并且程序员可以通过合适的方法来影响线程状态的切换。

  1. Thread 类的方法:
    • start():启动一个线程,使其处于就绪状态,等待系统调度执行。
    • sleep(long millis):让当前线程休眠指定的时间,线程状态从运行转为阻塞或超时等待状态。
    • join():等待线程终止,使当前线程进入等待状态。
    • interrupt():中断线程,让线程抛出 InterruptedException 异常,处于终止状态。
  1. Object 类的方法:
    • wait():让当前线程等待,使其进入等待状态,直到其他线程调用相同对象的 notify()notifyAll() 方法唤醒它。
    • notify() 和 notifyAll():用于唤醒一个或所有等待中的线程,使其从等待状态转为就绪状态
  1. LockSupport 类的方法:
    • park() 和 parkNanos(long nanos):阻塞当前线程,使其进入等待状态,可以通过 unpark(Thread thread) 方法唤醒指定线程。
  1. Thread 类的静态方法:
    • yield():提示调度器当前线程愿意放弃当前的 CPU 执行时间,使当前线程从运行状态转为就绪状态,但不一定会立即执行。

4. Thread.sleep() 方法和 Object.wait() 方法对比

共同点:两者都可以暂停线程的执行。

区别

  • sleep() 方法没有释放锁,而 wait() 方法释放了锁
  • wait() 通常被用于线程间交互/通信,sleep()通常被用于暂停执行。
  • wait() 方法被调用后,线程不会自动苏醒,需要别的线程调用同一个对象上的 notify()或者 notifyAll() 方法。sleep()方法执行完成后,线程会自动苏醒,或者也可以使用 wait(long timeout) 超时后线程会自动苏醒
  • sleep() 是 Thread 类的静态本地方法,wait() 则是 Object 类的本地方法。为什么这样设计呢?下一个问题就会聊到。

5. 为什么 wait() 方法不定义在 Thread 中?

wait()是让获得对象锁的线程实现等待,会自动释放当前线程占有的对象锁。每个对象(Object)都拥有对象锁,既然要释放当前线程占有的对象锁并让其进入 Waiting状态,自然是要操作对应的对象(Object)而非当前的线程(Thread)。

类似的问题:为什么 sleep() 方法定义在 Thread 中?

因为 sleep() 是让当前线程暂停执行,不涉及到对象类,也不需要获得对象锁。

6. 可以直接调用 Thread 类的 run 方法吗?

new 一个 Thread,线程进入了新建状态。调用 start()方法,会启动一个线程并使线程进入了就绪状态,当分配到时间片后就可以开始运行了start() 会执行线程的相应准备工作,然后自动执行 run() 方法的内容,这是真正的多线程工作。 但是,直接执行 run() 方法,会把 run() 方法当成一个 main 线程下的普通方法去执行,并不会在某个线程中执行它,所以这并不是多线程工作。

总结:调用 start() 方法方可启动线程并使线程进入就绪状态,直接执行 run() 方法的话不会以多线程的方式执行

7. 创建线程的方法

7.1. 继承Thread类

  • 定义一个类,继承自 Thread 类。
  • 重写 run() 方法,该方法包含线程的代码逻辑。
  • 创建该类的实例,并调用 start() 方法启动线程。

示例代码:

//1.继承Thread类
public class Client {
    public static void main(String[] args) {
        Thread thread = new MyThread();
        thread.start();
    }
}

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("继承Thread类创建线程");
    }
}

7.2. 实现Runnable接口

  • 定义一个类,实现 Runnable 接口。
  • 实现 run() 方法,该方法包含线程的代码逻辑。
  • 创建 Runnable 实例,将其作为参数传递给 Thread 类的构造函数。
  • 调用 Thread 实例的 start() 方法启动线程。

示例代码:

//2.实现Runnable接口
public class Client {
    public static void main(String[] args) {
        Runnable runnable = new MyRunnable();
        Thread thread = new Thread(runnable);
        thread.start();
    }
}

class MyRunnable  implements Runnable {

    @Override
    public void run() {
        System.out.println("实现Runnable接口创建线程");
    }
}

7.3. 实现Callable接口(带返回值的线程)

  • 定义一个类,实现 Callable 接口,并指定泛型为希望返回的类型
  • 实现 call() 方法,该方法包含线程的代码逻辑,并返回一个值
  • 创建 Callable 实例,并使用 ExecutorService 的 submit() 方法提交任务。
  • 调用 Future 对象的 get() 方法获取线程执行结果。
import java.util.concurrent.*;

class MyCallable implements Callable<String> {
    public String call() {
        // 线程执行的代码逻辑
        return "MyCallable is running";
    }
}

public class Client {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        //Executors 类:这是一个工厂类,提供了创建不同类型线程池的静态方法
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<String> future = executor.submit(new MyCallable());

        try {
            String result = fu.get();//获取线程执行结果
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }finally {
            service.shutdown();//关闭线程池
        }
    }
}

汇总:

public class Client {
    public static void main(String[] args) {
        //1.继承Thread类
        Thread t1 = new Thread() {
            @Override
            public void run() {
                System.out.println("继承Thread类创建线程");
            }
        };
        t1.start();

        //2.实现Runnable接口
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("实现Runnable接口");
            }
        });
        t2.start();

        //3.实现Callable接口
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<String> future = executor.submit(new Callable<String>(){
            @Override
            public String call() throws Exception {
                return null;
            }
        });
        try {
            String result = future.get();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }finally {
            executor.shutdown();//关闭线程池
        }
    }
}

8. 面试题:双线程交替打印数字

思路:

双线程交替打印有两种思路,一种是设置共享变量,控制当前线程应该打印哪个数,另一种是通过锁的互斥机制实现。第一种方法具备通用性,适用于各种线程同步问题,其原理是多个线程持有同一个锁,每个线程内部判断是否轮到自己执行,否则就等待;第二种方式只适用于两个线程交替执行的任务,其原理是通过wait和notify来实现线程间的通信,但两个线程都实现同一个Runnable接口,在Runnable接口中控制执行流程。

方法一(通用性方法):

public static void main(String[] args){
    public static int state = 0;
    public static Object lock = new Object();

    @Test
    public void testThread() {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    synchronized (lock) {
                        while (true) {
                            while (state % 2 != 0)
                                lock.wait();
                            System.out.println(Thread.currentThread().getName() + ":" + state);
                            state++;
                            Thread.sleep(1000);
                            lock.notifyAll();
                        }
                    }
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    synchronized (lock) {
                        while (true) {
                            while (state % 2 != 1)
                                lock.wait();
                            System.out.println(Thread.currentThread().getName() + ":" + state);
                            state++;
                            Thread.sleep(1000);
                            lock.notifyAll();
                        }
                    }
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        t1.start();
        t2.start();
}

方法二:

public static void main(String[] args){
    Runnable runnable = new MyRunnable();
    Thread t1 = new Thread(runnable);
    Thread t2 = new Thread(runnable);
    t1.start();
    t2.start();
}

class MyRunnable implements Runnable {
    private static int i = 1;

    @Override
    public void run() {
        while (true) {
            synchronized (this) {
                notify();
                System.out.println(Thread.currentThread().getName() + ": " + i++);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                try {
                    wait();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}

9. 面试题:交替打印ABC

9.1. 方法一:使用synchronized和wait/notify

synchronized是Java中的一个关键字,用于实现对共享资源的互斥访问。wait和notify是Object类中的两个方法,用于实现线程间的通信。wait方法会让当前线程释放锁,并进入等待状态,直到被其他线程唤醒。notify方法会唤醒一个在同一个锁上等待的线程。

我们可以使用一个共享变量state来表示当前应该打印哪个字母,初始值为0。当state为0时,表示轮到A线程打印;当state为1时,表示轮到B线程打印;当state为2时,表示轮到C线程打印。每个线程在打印完字母后,需要将state加1,并对3取模,以便循环。同时,每个线程还需要唤醒下一个线程,并让自己进入等待状态。

public class PrintABC {
 
    // 共享变量,表示当前应该打印哪个字母
    private static int state = 0;
 
    // 共享对象,作为锁和通信的媒介
    private static final Object lock = new Object();
 
    public static void main(String[] args) {
        // 创建三个线程
        Thread threadA = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    // 循环100次
                    for (int i = 0; i < 100; i++) {
                        // 获取锁
                        synchronized (lock) {
                            // 判断是否轮到自己执行
                            while (state % 3 != 0) {
                                // 不是则等待
                                lock.wait();
                            }
                            // 打印字母
                            System.out.println("A");
                            // 修改状态
                            state++;
                            // 唤醒下一个线程
                            lock.notifyAll();
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
 
        Thread threadB = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    for (int i = 0; i < 100; i++) {
                        synchronized (lock) {
                            while (state % 3 != 1) {
                                lock.wait();
                            }
                            System.out.println("B");
                            state++;
                            lock.notifyAll();
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
 
        Thread threadC = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    for (int i = 0; i < 100; i++) {
                        synchronized (lock) {
                            while (state % 3 != 2) {
                                lock.wait();
                            }
                            System.out.println("C");
                            state++;
                            lock.notifyAll();
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
 
        // 启动三个线程
        threadA.start();
        threadB.start();
        threadC.start();
    }
}

9.2. 方法二:使用ReentrantLock和Condition

ReentrantLock是Java中的一个类,用于实现可重入的互斥锁。Condition是ReentrantLock中的一个接口,用于实现线程间的条件等待和唤醒。ReentrantLock可以创建多个Condition对象,每个Condition对象可以绑定一个或多个线程,实现对不同线程的精确控制。

我们可以使用一个ReentrantLock对象作为锁,同时创建三个Condition对象,分别绑定A、B、C三个线程。每个线程在打印字母之前,需要调用对应的Condition对象的await方法,等待被唤醒。每个线程在打印字母之后,需要调用下一个Condition对象的signal方法,唤醒下一个线程。

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
 
public class PrintABC {
 
    // 共享变量,表示当前应该打印哪个字母
    private static int state = 0;
 
    // 可重入锁
    private static final ReentrantLock lock = new ReentrantLock();
 
    // 三个条件对象,分别绑定A、B、C三个线程
    private static final Condition A = lock.newCondition();
    private static final Condition B = lock.newCondition();
    private static final Condition C = lock.newCondition();
 
    public static void main(String[] args) {
        // 创建三个线程
        Thread threaA = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    // 循环100次
                    for (int i = 0; i < 100; i++) {
                        // 获取锁
                        lock.lock();
                        try {
                            // 判断是否轮到自己执行
                            while (state % 3 != 0) {
                                // 不是则等待
                                A.await();
                            }
                            // 打印字母
                            System.out.println("A");
                            // 修改状态
                            state++;
                            // 唤醒下一个线程
                            B.signal();
                        } finally {
                            // 释放锁
                            lock.unlock();
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
 
        Thread threaB = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    for (int i = 0; i < 100; i++) {
                        lock.lock();
                        try {
                            while (state % 3 != 1) {
                                B.await();
                            }
                            System.out.println("B");
                            state++;
                            C.signal();
                        } finally {
                            lock.unlock();
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
 
        Thread threaC = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    for (int i = 0; i < 100; i++) {
                        lock.lock();
                        try {
                            while (state % 3 != 2) {
                                C.await();
                            }
                            System.out.println("C");
                            state++;
                            A.signal();
                        } finally {
                            lock.unlock();
                        }
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
 
        // 启动三个线程
        threaA.start();
        threaB.start();
        threaC.start();
    }
}

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

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

相关文章

神器!3个免费PPT成品网站推荐+3款AIPPT工具盘点!

熬夜加班做PPT却没有头绪&#xff1f;别再自己憋着想了&#xff01;现在凡事主打一个“抄作业”&#xff0c;想做ppt却没想法&#xff0c;可以去到ppt成品网站搜集PPT模板&#xff0c;或是使用时下流行的AI生成PPT工具&#xff0c;只需输入PPT主题&#xff0c;即可快速生成一份…

Linux 命令探秘:揭秘那些有趣的小命令

目录 1.发现隐藏在终端的惊喜小命令 2.小火车 1.安装EPEL 2.小火车出发准备 3.输入命令 3.linux_logo 1.安装linux_logo 2.输入命令 3.linux_logo介绍 4.牛讲话 1.安装命令 2.输入命令 5. figlet 1.安装命令 2.输入命令 “如果您在解决类似问题时也遇到了困…

前端面试题49(如何集成和使用CSP 来增强前端安全性?)

Content Security Policy (CSP) 是一种帮助防止跨站脚本(XSS)和其他代码注入攻击的安全策略。通过明确指定浏览器可以加载或执行哪些资源&#xff0c;CSP 有效限制了恶意内容的执行。下面是如何在实际项目中集成和使用 CSP 的步骤&#xff1a; 1. 确定CSP策略 首先&#xff0…

欧科云链研究院:坎昆升级后,Layer2变得更好了吗?

本文由欧科云链研究院OKG Research联合PANews出品&#xff1a;以数据为导向&#xff0c;洞察真实的链上世界。 作者&#xff5c;Jason Jiang, OKG Research 坎昆升级后&#xff0c;以太坊L2的交易费用降低明显且吞吐量有所提升&#xff0c;但整体生态并没有迎来想象中的繁荣景…

leetcode165.解密数字

题目表述&#xff1a; 这道题目和斐波那契数列以及跳台阶问题十分相似。 斐波那契数列&#xff1a;0、1、1、2、3、5, 8、13、21、34 …… leetcode跳台阶问题&#xff1a;1、1、2、3、5, 8、13、21、34....... 这类题目的特点都是第N项的结果等于前两项的和。 但是解密数…

Spring中的单例模式应用详解

1. DefaultListableBeanFactory 在Spring中&#xff0c;所有由Spring容器管理的Bean默认都是单例的。Spring框架中最经典的单例模式实现是在BeanFactory中。BeanFactory是Spring IoC容器的核心接口&#xff0c;其实现类DefaultListableBeanFactory在加载Bean定义时&#xff0c…

手机m4a怎么转换成mp3,手机端即可完成格式转换

M4A&#xff08;MPEG-4 Audio&#xff09;是一种无损压缩的音频格式&#xff0c;通常用于苹果设备和 iTunes 上&#xff0c;因为它能提供较高的音质同时占用较小的存储空间。 然而&#xff0c;MP3 作为最普及的音频格式之一&#xff0c;兼容性更强&#xff0c;几乎所有的播放设…

【代码随想录】【算法训练营】【第65天】 [卡码94]城市间货物运输I

前言 思路及算法思维&#xff0c;指路 代码随想录。 题目来自 卡码网。 day 65&#xff0c;周四&#xff0c;继续ding~ [卡码94] 城市间货物运输I 题目描述 卡码94 城市间货物运输I 解题思路 前提&#xff1a; 思路&#xff1a; 重点&#xff1a; 代码实现 C语言 Be…

maven7——(重要,构建项目)maven项目构建(命令)

Maven的常用命令管理项目的生命周期 clean命令 清除编译产生的target文件夹内容&#xff0c;可以配合相应命令在cmd中使用&#xff0c;如mvn clean package&#xff0c; mvn clean test D:\工作\公司培训-4班\day20\day20\untitled1>mvn clean compile命令 该命令可以…

C语言之指针的奥秘(二)

一、数组名的理解 int arr[10]{1,2,3,4,5,6,7,8,9,10}; int *p&arr[0]; 这里使用 &arr[0] 的⽅式拿到了数组第⼀个元素的地址&#xff0c;但是其实数组名本来就是地址&#xff0c;而且是数组首元素的地址。如下&#xff1a; 我们发现数组名和数组⾸元素的地址打印出…

电影购票小程序论文(设计)开题报告

一、课题的背景和意义 随着互联网技术的不断发展&#xff0c;人们对于购票的需求也越来越高。传统的购票方式存在着排队时间长、购票流程繁琐等问题&#xff0c;而网上购票则能够有效地解决这些问题。电影购票小程序是网上购票的一种新型应用&#xff0c;它能够让用户随时随地…

电气工程VR虚拟仿真实训平台以趣味化方式增强吸引力

在工业4.0时代和教育信息化的双重推动下&#xff0c;我们致力于推动实训课件的跨界合作与共创。VR实训课件不仅促进了不同领域、不同行业之间的紧密合作&#xff0c;更让学习变得生动直观。我们凭借3D技术生动、直观、形象的特点&#xff0c;开发了大量配套3D教材&#xff0c;让…

vue-router history 模式下将所有资源文件js/css/img都存放在oss 利用 cdn 访问整体思路汇总

背景 我们有一个域名https://example.com&#xff0c;但是ssl证书很贵&#xff0c;搞子域名来承接新站点有点费钱&#xff0c;所以我们想用一个目录https://example.com/admin/ 来作为管理后台的站点&#xff0c;这个站点是单页面应用&#xff0c;我又想让其用history router的…

C++入门到进阶(图文详解,持续更新中)

C入门到进阶&#xff08;图文详解&#xff0c;持续更新中&#xff09; 目录 C入门到进阶&#xff08;图文详解&#xff0c;持续更新中&#xff09; 数据 数据类型 基本数据类型/内置数据类型 C常用运算符 赋值运算符 关系运算符 逻辑运算符 杂项运算符 数据的本地化…

VBA即用型代码手册:删除完全空白的行

我给VBA下的定义&#xff1a;VBA是个人小型自动化处理的有效工具。可以大大提高自己的劳动效率&#xff0c;而且可以提高数据的准确性。我这里专注VBA,将我多年的经验汇集在VBA系列九套教程中。 作为我的学员要利用我的积木编程思想&#xff0c;积木编程最重要的是积木如何搭建…

Hadoop的HA模式搭建

准备三台虚拟机 bigdata007&#xff0c;bigdata008&#xff0c;bigdata009 1.前置工作 1.修改虚拟机的IP地址和hostname 2.配置集群中的ip映射&#xff08;/etc/hosts&#xff09; 192.168.111.57 bigdata007 192.168.111.58 bigdata008 192.168.111.59 bigdata0093.关闭虚拟…

千万慎投!自引率高达93%!这16本On hold正处于高危状态,无法检索,剔除岌岌可危中!近四年镇压期刊“出狱”情况一览

本周投稿推荐 SCI • 能源科学类&#xff0c;1.5-2.0&#xff08;25天来稿即录&#xff09; • CCF推荐&#xff0c;4.5-5.0&#xff08;2天见刊&#xff09; • 生物医学制药类&#xff08;2天逢投必中&#xff09; EI • 各领域沾边均可&#xff08;2天录用&#xff09…

昇思25天学习打卡营第19天|LSTM+CRF序列标注

概述 序列标注指给定输入序列&#xff0c;给序列中每个Token进行标注标签的过程。序列标注问题通常用于从文本中进行信息抽取&#xff0c;包括分词(Word Segmentation)、词性标注(Position Tagging)、命名实体识别(Named Entity Recognition, NER)等。 条件随机场&#xff08…

thinkphp 生成邀请推广二维码,保存到服务器并接口返回给前端

根据每个人生成自己的二维码图片,接口返回二维码图片地址 生成在服务器的二维码图片 控制器 public function createUserQRcode(){$uid = input(uid);if

【VUE进阶】安装使用Element Plus组件

Element Plus组件 安装引入组件使用Layout 布局button按钮行内表单菜单 安装 包管理安装 # 选择一个你喜欢的包管理器# NPM $ npm install element-plus --save# Yarn $ yarn add element-plus# pnpm $ pnpm install element-plus浏览器直接引入 例如 <head><!-- I…