简单了解java中线程的使用

news2025/3/1 13:29:35

线程

1、线程的相关概念

1.1、并行和并发

并行:在同一时刻,有多个任务在多个CPU上同时执行

并发:在同一时刻,有多个任务在单个CPU上交替执行

1.2、进程和线程

进程:就是在多任务管理系统中,每个独立执行的程序,进程就是”正在进行的程序“

线程:就是程序运行的基本单元。当操作系统执行一个程序时,会在系统中建立一个进程,该进程必须至少建立一个线程(这个线程被称为主线程)作为这个程序运行的入口点。因此,在操作系统中运行的任何程序都至少有一个线程

2、什么是多线程?

是指从软件或者硬件上实现多个线程并发执行的技术。

具有多线程能力的计算机因为硬件支持而能够在同一时间执行多个线程,提升性能。

3、线程的使用

3.1、使用多线程的好处

提高程序的效率

3.2、多线程如何开发

3.2.1、线程启动方式之Thread类(java语言提供的线程类)

概述:java.lang.Thread是线程类,可以用来给进程创建线程处理任务使用,其中线程中有两个中要的方法:

  • public void run():线程执行任务的方法,是线程启动后第一个执行的方法
  • public void start():启动线程的方法,线程对象调用该方法后,Java虚拟机就会调用此线程的run方法

线程启动步骤:

  • 创建一个子类继承Thread类(创建的子类也是线程类)
  • 在子类中,编写让线程完成的任务(任务代码)
  • 重写Thread类中的run方法(线程任务)
  • 启动线程

示例:

创建一个子类线程:

public class MyThread extends Thread{
    @Override
    public void run() {
        System.out.println("我的线程开始啦");
        for (int i = 100; i < 200; i++) {
            System.out.println("我的线程:" + i);
        }
    }
}

在main中启动子线程

public class ThreadDemo1 {
    public static void main(String[] args) {
        //创建一个线程对象
        MyThread myThread = new MyThread();

        //启动线程
        myThread.start();

        //主线程代码
        for (int i = 0; i < 100; i++) {
            System.out.println("主线程:" + i);
        }
    }
}

结果展示(展示部分):

主线程:0
我的线程开始啦
主线程:1
我的线程:100
我的线程:101
我的线程:102
主线程:2
我的线程:103
主线程:3
我的线程:104
我的线程:105
我的线程:106
主线程:4
主线程:5
我的线程:107
主线程:6
我的线程:108
主线程:7
主线程:8
主线程:9
主线程:10
主线程:11
主线程:12
主线程:13
主线程:14
我的线程:109
主线程:15
我的线程:110
我的线程:111
我的线程:112
我的线程:113
我的线程:114
我的线程:115
主线程:25
...
3.2.2、线程启动方式之Runnable接口(推荐使用,灵活度高,因为允许子类继承其他父类)

使用的构造方法:

  • public Thread(Runnable target)

  • public Thread(Runnable target, String name)

参数中的Runnable是一个接口,用来定义线程要执行的任务

线程启动步骤:

  • 定义任务类实现Runnable,并重写run方法
  • 创建任务对象
  • 使用含有Runnable参数的构造方法,创建线程对象并指定任务
  • 调用线程start方法,开启线程

示例:

任务类

public class MyTask implements Runnable{
    @Override
    public void run() {
        for (int i = 100; i < 200; i++) {
            System.out.println("新线程:"+ i);
        }
    }
}

启动线程

public class ThreadDemo1 {
    public static void main(String[] args) {
        MyTask myTask = new MyTask();

        Thread t = new Thread(myTask);

        t.start();

        for (int i = 0; i < 100; i++) {
            System.out.println("主线程:" + i);
        }
    }
}

运行结果与上面相似

4、线程中的常用方法

方法说明
String getName()获取线程名字
viod setName()给线程设置一个名字
public static Thread currentThread()返回当前正在执行的线程对象的引用
public static void sleep(long time)让线程休眠指定的时间,单位为毫秒
public void join()具备阻塞作用,等待这个线程死亡,才会执行其他线程

获取线程名字示例:

public class ThreadTask implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 30; i++) {
            //获取                     当前线程          的名字
            System.out.println(Thread.currentThread().getName() + ": " + i);
        }
    }
}


public class Test1 {
    public static void main(String[] args) {
        new Thread(new ThreadTask()).start();

        for (int i = 100; i <120 ; i++) {
            System.out.println(Thread.currentThread().getName() + ": " + i);
        }
    }
}

运行结果(部分展示):

main: 100
Thread-0: 0
main: 101
Thread-0: 1
main: 102
Thread-0: 2
main: 103
Thread-0: 3
main: 104
Thread-0: 4
main: 105

其他方法,大家可以自行尝试。

5、线程的安全问题

5.1、发生安全问题的原因

多个线程对同一个数据,进行读写操作,造成数据错乱

案例分析:我们现在设计一个卖票程序,票数总共100张,设置三个售票处

思路:

  • 定义一个类Ticket实现Runnable接口,里面定义一个成员变量Private int count = 100
  • 在Ticket类中重写run()方法实现卖票,代码如下

Ticket类

public class Ticket implements Runnable{
    private int count = 100;

    @Override
    public void run() {
        while (true){
            if(count > 0){

                //模拟出票时间延迟
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

                System.out.println(Thread.currentThread().getName() + "票号:" + count);
                count--;
            }
            if(count == 0){
                break;
            }
        }
    }
}

Test类

public class Test {
    public static void main(String[] args) {
        Ticket ticket = new Ticket();

        //三个售票处
        Thread t1 = new Thread(ticket, "售票处1-");
        Thread t2 = new Thread(ticket, "售票处2-");
        Thread t3 = new Thread(ticket, "售票处3-");

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

当我们运行后,发现结果出现了问题,有些情况不在我们的预期之中,不符合常理

比如出现了重复票:

售票异常1

还有出现了0号票:

售票异常2

为什么会出现这些奇怪的问题呢?很简单,这是因为多线程操作共享数据。解决这些问题的基本思路就是让共享数据存在安全环境中,当某一个线程访问共享数据时,其他线程是无法操作的

具体实现:

  • 把多条线程操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可
  • java提供了同步代码块的实现方式来解决

5.2、同步代码块

5.2.1、线程同步

java允许多线程并发执行,当多个线程同时操作一个可共享的资源变量时(比如数据的增删改查),将会导致数据不准确,相互之间产生冲突,因此加入同步锁,以避免在该线程没有完成操作之前,被其它线程调用,从而保证该变量的唯一性和准确性

5.2.2、同步代码块

锁住多条语句操作共享数据,可以使用同步代码块实现

  • 格式:
synchronized(任意对象){
    多条件语句操作共享数据的代码
}
  • 默认情况锁是打开的,只要有一个线程进去执行代码了,锁就会关闭
  • 当线程执行完成出来后,锁才会自动打开
  • 锁对象是任意对象,但是多个线程必须使用同一把锁

同步的好处和弊端:

  • 好处:解决了多线程的数据安全问题
  • 弊端:当线程很多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率

所以上面Ticket类中可以修改为:

public class Ticket implements Runnable{
    private int count = 100;

    Object lock = new Object();

    @Override
    public void run() {
        while (true){
            synchronized (lock){//锁对象可以时任意对象
                if(count > 0){

                    //模拟出票时间延迟
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }

                    System.out.println(Thread.currentThread().getName() + "票号:" + count);
                    count--;
                }
                if(count <= 0){
                    break;
                }
            }
        }
    }
}
5.2.3、同步方法

**概念:**就是把synchronized关键字加到方法上,保证线程执行该方法的时候,其他线程只能在方法外等着

  • 格式
修饰符 synchronized 返回值类型 方法名(方法参数){

}
  • 同步代码块和同步方法的区别

    同步代码块可以锁住指定代码,同步方法是锁住方法中的所有代码

    同步代码块可以指定锁对象,同步方法不能指定锁对象

虽然同步方法不能指定锁对象,但是有默认存在的锁对象

对于非static方法,同步锁就是this

对于static方法,我们使用当前方法所在类的字节码对象(类名.class)。Class类型的对象

public class Ticket implements Runnable{
    private int count = 100;

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

            demo();
        }
    }

    private synchronized void demo(){
        if(count > 0){

            //模拟出票时间延迟
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

            System.out.println(Thread.currentThread().getName() + "票号:" + count);
            count--;
        }
    }
}

6、Lock锁机制

虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了它,为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock。

Lock中提供了获得锁和释放锁的方法

  • void lock():获得锁
  • void unlock():释放锁

Lock是接口不能实例化,这里采用它的实现类ReentrantLock来实例化,ReentrantLock的构造方法是:ReentrantLock()。

注意:多个线程使用相同的Lock锁对象,需要多线程操作数据的代码放在lock()和unlock()方法之间。一定要确保最后unlock能够调用

上述Ticket类可以修改为这样:

public class Ticket implements Runnable{
    private int count = 100;

    //获取锁对象
    Lock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true){
            //上锁
            lock.lock();
            if(count <= 0){
                break;
            }

            if(count > 0){

                //模拟出票时间延迟
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }

                System.out.println(Thread.currentThread().getName() + "票号:" + count);
                count--;
            }
            //释放锁
            lock.unlock();
        }
    }
}

7、线程通讯

7.1、概念

在多线程程序中,某个线程进入到等待状态时,必须有其他线程来唤醒处于等待状态的线程。

7.2、线程通讯需要使用的API

7.2.1、等待方法
  • wait():无线等待(只能由其他线程唤醒)
  • wait(long 毫秒):计时等待,时间到了自动唤醒

以上两个方法调用会导致当前线程释放掉锁资源

7.2.3、唤醒方法
  • notify():唤醒处于等待状态的任意个线程
  • notityAll():唤醒处于等待状态的所有线程

以上两个方法调用不会导致当前线程释放掉锁资源

无限等待唤醒示例:

public class Test {
    public static void main(String[] args) {
        Runnable task = new Runnable() {
            Object lock = new Object();
            boolean flag = true;

            @Override
            public void run() {
                synchronized (lock){
                    if(flag){
                        flag = false;
                        System.out.println("线程进入无限等待...");
                        try {
                            lock.wait();
                            System.out.println("程序继续执行啦~");
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }else{
                        System.out.println("线程即将被唤醒");
                        try {
                            Thread.sleep(2000);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                        lock.notify();
                    }
                }
            }
        };

        new Thread(task).start();
        new Thread(task).start();
    }
}

计时等待唤醒示例:

public class Test01 {
    public static void main(String[] args) {
        new Thread(() -> {
            Object lock = new Object();

           synchronized (lock){
               try {
                   System.out.println("即将进入计时等待...");
                   lock.wait(2000);
                   System.out.println("两秒了,程序继续执行");
               } catch (InterruptedException e) {
                   throw new RuntimeException(e);
               }
           }
        }).start();
    }
}

总结:

  • 等待和唤醒方法调用需要使用对象锁,需要在同步代码中完成
  • wait()进入无限等待,wait(时间)进入计时等待
  • 唤醒线程的方法是notify【唤醒处于和notify使用同一对象锁上的,处于等待状态的任意线程】、notifyAll【同notify】

最后给大家来一个经典的生产者消费者简单线程代码示例:

公共资源类

public class Food {
    //判断是否有食物
    public static boolean food = true;

    //锁
    public static final Object lock = new Object();
}

生产者

public class Producer implements Runnable{
    @Override
    public void run() {
        synchronized (Food.lock){
            while(true){
                //判断是否有食物,有食物则进行等待,反之则生产食物
                if(Food.food){
                    //将食物标识设置为无
                    //Food.food = false;

                    System.out.println(Thread.currentThread().getName() + "此时进行等待消费者消费~");

                    try {
                        Food.lock.wait();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }else{
                    System.out.println(Thread.currentThread().getName() + "发现没有食物,开始生产~");

                    //制作食物的时间
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    Food.food = true;

                    //唤醒消费者
                    Food.lock.notify();
                }
            }
        }
    }

    public Producer() {
    }
}

消费者

public class Consumer implements Runnable{
    @Override
    public void run() {
        //判断是否有食物,有则消费,没有则等待
        synchronized (Food.lock){
            while(true){
                if(Food.food){
                    System.out.println(Thread.currentThread().getName() + "发现食物,开炫~");

                    //消费时长
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    Food.food = false;

                    //唤醒生产者继续生产
                    Food.lock.notify();
                }else{
                    System.out.println(Thread.currentThread().getName() + "没有发现食物,叫厨师~");

                    try {
                        Food.lock.wait();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
    }

    public Consumer() {
    }
}

测试类

public class Test {
    public static void main(String[] args) {
        new Thread(new Producer(), "生产者").start();
        new Thread(new Consumer(), "消费者").start();
    }
}

部分运行结果

生产者此时进行等待消费者消费~
消费者发现食物,开炫~
消费者没有发现食物,叫厨师~
生产者发现没有食物,开始生产~
生产者此时进行等待消费者消费~
消费者发现食物,开炫~
消费者没有发现食物,叫厨师~
......

8、线程池

8.1、概述

8.1.1、线程使用存在的问题

如果并发的线程数量很多,并且每个线程都是执行一个很短的任务就结束了,这样频繁的创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。

如果大量线程在执行,会涉及到线程间上下文的切换,会极大的消耗CPU运算资源

8.1.2、线程池认识

其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源

8.1.3、线程池使用的大致流程
  • 创建线程池,指定线程开启数量
  • 提交任务给线程池,线程池中的线程就会获取任务,进行任务处理
  • 线程处理完任务不会销毁,而是返回到线程池中,等待下一个任务执行
  • 如果线程池中所有的线程都被占用,提交任务,只能等待线程池中的线程处理完当前任务
8.1.4、线程池的好处
  • 降低资源消耗:减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可以执行多个任务。
  • 提高响应速度:当任务到达时,任务可以不需要等待线程创建,就能立即执行
  • 提高线程的可管理性:可以根据系统的承受能力,调整线程池中工作线线程池的数目,防止因为消耗过多内存,服务器死机。

8.2、线程池中的API

8.2.1、线程池API学习

java.util.concurrent.ExecutorService是线程池接口类型,使用时我们不需要自己实现,JDK已经帮我们实现好了。获取线程池我们使用工具类java.util.concurrent.Executor的静态方法。

public static ExecutorService newFixedThreadPool(int num)指定线程池最大线程池数量获取线程池

线程池ExcutorService的相关方法:

提交执行的任务方法

< T>Future< T>submit(Callable< T> task)

Future< ?> submit(Runnable task)

关闭线程池方法

void shutdown() 启动一次顺序关闭,执行以前提交任务,但不接受新任务

示例:有三个老师要对五个学生进行一对一辅导:

public class Pool implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "在辅导学生学习");
    }
}

public class Test {
    public static void main(String[] args) {
        ExecutorService pool = Executors.newFixedThreadPool(3);

        pool.submit(new Pool());
        pool.submit(new Pool());
        pool.submit(new Pool());
        pool.submit(new Pool());
        pool.submit(new Pool());
    }
}

测试结果:

pool-1-thread-2在辅导学生学习
pool-1-thread-1在辅导学生学习
pool-1-thread-3在辅导学生学习
pool-1-thread-1在辅导学生学习
pool-1-thread-2在辅导学生学习

8.3、Callable接口

8.3.1、概述
public interface Callable<V> {
	V call() throws Exception;
}

Callable和Runnable的不同点:

  • Callable支持返回结果,Runnable不行
  • Callable支持抛出异常,Runnable不行
8.3.2、使用步骤
  • 创建线程池
  • 定义Callable任务
  • 创建Callable任务,提交任务给线程池
  • 获取执行结果

利用线程池计算0-n的和并返回结果:

public class CallableDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService demo = Executors.newFixedThreadPool(10);

        Callable<Integer> task = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int sum = 0;
                for (int i = 1; i <= 10; i++) {
                    sum += i;
                }
                return sum;
            }
        };

        Future<Integer> future = demo.submit(task);
        System.out.println(future.get());
    }
}

ble和Runnable的不同点:**

  • Callable支持返回结果,Runnable不行
  • Callable支持抛出异常,Runnable不行
8.3.2、使用步骤
  • 创建线程池
  • 定义Callable任务
  • 创建Callable任务,提交任务给线程池
  • 获取执行结果

利用线程池计算0-n的和并返回结果:~

public class CallableDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        ExecutorService demo = Executors.newFixedThreadPool(10);

        Callable<Integer> task = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int sum = 0;
                for (int i = 1; i <= 10; i++) {
                    sum += i;
                }
                return sum;
            }
        };

        Future<Integer> future = demo.submit(task);
        System.out.println(future.get());
    }
}

呼~~~

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

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

相关文章

【MySQL】表的基本增删查改(结合案例)

文章目录 1.前言2.插入数据&#xff08;Create&#xff09;2.1案例2.2单行数据全列插入2.3多行数据指定列插入2.4插入否则更新2.5替换 3. 读取数据(Retireve)3.1案例3.2全列查询3.3指定列查询3.4查询字段为表达式3.5为查询结果起别名3.6去重3.7where条件3.7.1案例 3.8排序3.9筛…

Post Microsoft Build and AI Day 北京开发者日

Microsoft Build 开发者大会 Microsoft Build 开发者大会是微软每年一次的开发者技术盛会&#xff0c;旨在向全球开发者展示微软最新的技术、产品和服务。 刚刚过去的 2024 Microsoft Build 开发者大会围绕 Copilot、生成式 AI、应用程序安全、云平台、低代码等多个技术方向&a…

运维系列.在Docker中使用Grafana

运维专题 在Docker中使用Grafana - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.net/qq_2855026…

Java对象的序列化与反序列化

序列化和反序列化是什么 当两个进程远程通信时&#xff0c;彼此可以发送各种类型的数据。无论是何种类型的数据&#xff0c;都会以二进制序列的形式在网络上传送。比如&#xff1a;我们可以通过http协议发生字符串信息&#xff1b;我们也可以在网络上直接发生Java对象。发送方…

【linux】信号(三)

本章节将会围绕信号处理进行展开讲解 目录 回顾一下&#xff1a;历史问题&#xff1a;内核态 VS 用户态地址空间&#xff1a;键盘的输出如何被检测到&#xff1a;OS如何正常运行&#xff1a;如何执行系统调用&#xff1a; 信号的处理&#xff1a;sigaction&#xff1a;信号的…

QML学习十九:ttf字体库使用

一、前言 在使用QML时&#xff0c;常常自定义按钮&#xff0c;按钮上有显示个图标&#xff0c;其实&#xff0c;那不是图标&#xff0c;是文本&#xff0c;如何显示&#xff1f; 本篇记录&#xff0c;如何导入阿里巴巴字体库&#xff0c;并调用显示。 二、阿里巴巴字体库下载…

分布式系统设计指南

目录 一、分布式简介 二、分布式系统核心概念 2.1 CAP 理论 2.2 BASE 原理 三、分布式系统设计 3.1 微服务拆分 3.2 通信模型 3.3 负载均衡 3.4 数据一致性 3.5 容错限流 3.6 扩展性 3.7 监控预警 3.8 自动化运维 一、分布式简介 分布式系统是由单体应用发展而来的&#xff…

统计绘图 | 既能统计分析又能可视化绘制的技能

在典型的探索性数据分析工作流程中&#xff0c;数据可视化和统计建模是两个不同的阶段&#xff0c;而我们也希望能够在最终的可视化结果中将相关统计指标呈现出来&#xff0c;如何让将两种有效结合&#xff0c;使得数据探索更加简单快捷呢&#xff1f;今天这篇推文就告诉你如何…

使用 Scapy 库编写 TCP 窗口大小探测攻击脚本

一、介绍 1.1 概述 TCP窗口大小探测攻击是一种信息收集攻击&#xff0c;攻击者通过向目标服务器发送特制的TCP数据包&#xff0c;探测目标服务器的TCP接收窗口大小&#xff08;TCP Window Size&#xff09;。了解目标服务器的TCP接收窗口大小&#xff0c;可以帮助攻击者优化后…

Spring Web MVC之过滤器Filter和拦截器HandlerInterceptor的区别和用法

作用时机不一样 Spring 框架有一个很重要的类DispatcherServlet。这个类继承了HttpServlet&#xff0c;HttpServlet实现了Servlet接口。相当于图片中的Servlet。所有和Spring框架相关配置&#xff0c;例如注解、xml配置、其他数据库连接配置、bean配置、拦截器配置等其他配置&…

深度学习研究生的职业前景:未来趋势与机遇

deep learning 深度学习研究生的职业前景&#xff1a;未来趋势与机遇一、深度学习的应用领域1. 计算机视觉2. 自然语言处理&#xff08;NLP&#xff09;3. 数据分析4. 游戏开发5. 健康医疗 二、职业机遇与挑战1. 工作机会2. 竞争与挑战3. 薪资前景 三、职业发展策略对于深度学习…

国外创意二维码应用:飞利浦旧物翻新活动,传播可持续性消费的重要性!

你知道去年有超过1000万件礼物被扔进了垃圾场吗? 这些被丢弃的物品中有许多仍在使用&#xff0c;飞利浦希望改变这种浪费现象。 去年的地球日&#xff0c;飞利浦策划了一场名为“Better than New” 的二维码营销活动。他们发布了一个视频&#xff0c;通过这个短视频将所有最终…

钉钉魔点指纹考勤机多少钱一台,指纹门禁考勤一体机价格

钉钉魔点指纹考勤机一台多少钱呢&#xff0c;指纹门禁考勤一体机的价格又是多少 钉钉魔点 X2 智能指纹考勤门禁一体机的参考价格是 359 元。 其具体参数情况如下&#xff1a; 产品类型&#xff1a;属于指纹考勤门禁一体机&#xff1b; 验证方式&#xff1a;为电容指纹&…

4、优化阶段

优化概述 编译程序总框架&#xff1a; 优化:对程序进行各种等价变换&#xff0c;使得从变换后的程序出发&#xff0c;能生成更有效的目标代码。 等价:不改变程序的运行结果。 有效:目标代码运行时间短&#xff0c;占用存储空间小。 >目的 产生更高效的代码 >遵循的原则 …

618值得购买的东西有哪些?618四款必囤好物清单分享!

随着618购物狂欢节的脚步日益临近&#xff0c;身为数码领域的资深爱好者&#xff0c;我深感有必要为大家推荐一系列经过精心挑选的数码产品精选。无论是热衷于科技前沿的探索者&#xff0c;还是希望通过智能设备提升生活品质的时尚达人&#xff0c;本文所介绍的每一款数码产品都…

MT2096 数列分段

代码&#xff1a; #include <bits/stdc.h> using namespace std; const int N 1e5 10; int n, m; int a[N]; int ans 1; int main() {cin >> n >> m;for (int i 1; i < n; i)cin >> a[i];int num 0;for (int i 1; i < n; i){if (num a[i…

(1)图像识别yolov5—安装教程

目录 1、安装YOLOv5: 2、下载预训练模型: 3、识别示例图片: 1、安装YOLOv5: 首先,你需要在你的计算机上下载 YOLOv5 的文件包,下载链接:https://github.com/ultralytics/yolov5。下载后对压缩文件进行解压。 通常使用 YOLOv5 识别物体,需要安装必要的 依赖…

DataX(DataX简介、部署、同步数据)

DataX&#xff08;DataX简介、部署、同步数据&#xff09; ☀快乐无限 法力无边 目录 DataX&#xff08;DataX简介、部署、同步数据&#xff09; 1.DataX简介 1&#xff09;数据采集模块&#xff1a; 2&#xff09;数据写入模块&#xff1a; 2.DataX部署 1&#xff09;Da…

《AI企业级知识库》-rasa爆改中文版本-实战!

阿丹&#xff1a; 之前有同学反应分享的东西有点概念化&#xff0c;表示不看着代码无法更深刻能理解。那么今天直接上代码&#xff01;&#xff01;&#xff01; 有两种方式使用自己训练好的nlu 1、rasa与nul分开启动&#xff0c;就是在rasa中的配置中配置好目标对应的nlu的服…

语法04 C++ 标准输入语句

标准输入 使用格式&#xff1a;cin >> 输入的意思就是把一个值放到变量里面去&#xff0c;也就是变量的赋值&#xff0c;这个值是由我们自己输入的。 (注意:输入变量前要先定义&#xff0c;输入完之后要按Enter键。) 输入多个变量&#xff0c;与输出类似&#xff0c;…