java多线程

2023-05-16

Java多线程并发

什么是多线程

  • 线程:程序内部的一条执行路径(比如说我们之前学的main方法就是一条单独的执行路线)
  • 单线程:程序中如果只有一条执行路径,那么这个程序就是单线程的程序。
  • 多线程:多线程是指从软硬件上实现多条执行流程的技术

为什么要使用多线程

提高CPU的利用率,更好地利用系统资源

举个生活中的例子:假设说我现在的任务有:

  1. 煲汤(假设煲好汤需要两小时)
  2. 学习Java两小时

那么单线程的做法可能是:准备食材->开始煲汤->等待两小时后->开始学习java两小时(耗时四个小时)
而多线程的做法是:准备食材->开始煲汤->煲汤的同时开始学习java两小时(耗时两个小时)

可以看到,在单线程的处理方式中,我有两个小时是什么都没有做的,相当于是浪费了资源
现在将例子中的我看作cpu,煲汤的过程看作io输出打印东西,学习Java看作其他任务,也就是说
单线程中,在io输出的那两个小时中,cpu一直在等待,而多线程中,cpu在等待的过程中去处理了其他任务,相当于同时完成了两个任务,充分提高了cpu的利用率。

如何创建多线程

四种方式:

  1. 继承Thread类
  2. 实现Runnable接口
  3. 实现Callable接口( JDK1.5>= )
  4. 线程池方式创建
继承Thread类

创建步骤:

  1. 定义一个子类MyThread继承线程类java.lang.Thread,重写run()方法
  2. 创建MyThread类的对象
  3. 调用线程对象的start()方法启动线程(启动后还是执行run方法的)
public class MyThread extends Thread{//定义一个子类MyThread继承线程类java.lang.Thread
    public void run(){//重写run()方法
        for (int i = 0; i < 5; i++) {
            System.out.println("MyThread run");
        }
    }
}

public class Main {
    public static void main(String[] args) {
       Thread mythread=new MyThread();//创建MyThread类的对象
       mythread.start();//调用线程对象的start()方法启动线程(启动后还是执行run方法的)
       run();//主线程的方法
    }

    public static void run(){
        for (int i = 0; i < 5; i++) {
            System.out.println("Main run");
        }
    }
}

运行结果:

Main run
MyThread run
MyThread run
MyThread run
MyThread run
MyThread run
Main run
Main run
Main run
Main run

Process finished with exit code 0

可以看到,两个线程并发执行。
Thread 类本质上是实现了 Runnable 接口的一个实例,代表一个线程的实例。启动线程的唯一方
法就是通过 Thread 类的 start()实例方法。start()方法是一个 native 方法,它将启动一个新线
程,并执行 run()方法。

源码:

public class Thread implements Runnable {
    ...
}

@FunctionalInterface
public interface Runnable {
    /**
     * When an object implementing interface {@code Runnable} is used
     * to create a thread, starting the thread causes the object's
     * {@code run} method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method {@code run} is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}
  1. 为什么不直接调用了run方法,而是调用start启动线程。

直接调用run方法会当成普通方法执行,此时相当于还是单线程执行。
只有调用start方法才是启动一个新的线程执行。

  1. 把主线程任务放在子线程之前了。

这样主线程一直是先跑完的,相当于是一个单线程的效果了。

实现Runnable接口

可能有人会问,既然方式一里Thread都实现Runnable接口了,为什么还要学这种方式?

因为方式一线程类继承Thread后,不能继承其他类,不便于扩展,这也是方式一的缺点

创建步骤:

  1. 定义一个线程任务类MyRunnable实现Runnable接口,重写run()方法
  2. 创建MyRunnable任务对象
  3. 把MyRunnable任务对象交给Thread处理。
  4. 调用线程对象的start()方法启动线程

emmm…相当于多套了一层:封装Runnable对象成为线程对象,Runnable接口里只定义了一个抽象run方法
那我们不妨先看看Thread提供了哪些构造器?
1.jpg

public class MyRunnable implements Runnable{//定义一个线程任务类MyRunnable实现Runnable接口
    public void run(){//重写run()方法
        for (int i = 0; i < 5; i++) {
            System.out.println("MyThread run");
        }
    }
}

public class Test01 {
    public static void main(String[] args) {
        Runnable r=new MyRunnable();//创建MyRunnable任务对象
        Thread thread=new Thread(r);//把MyRunnable任务对象交给Thread处理。
        thread.start();
        run();
    }
    public static void run(){//调用线程对象的start()方法启动线程
        for (int i = 0; i < 5; i++) {
            System.out.println("Main run");
        }
    }
}

运行结果:

Main run
Main run
Main run
Main run
MyThread run
MyThread run
MyThread run
MyThread run
MyThread run
Main run

方式二的简化写法:匿名内部类

public class Test01 {
    public static void main(String[] args) {

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    System.out.println("MyThread run");
                }
            }
        }).start();
        run();
    }
    public static void run(){
        for (int i = 0; i < 5; i++) {
            System.out.println("Main run");
        }
    }
}

再次简写:lambda表达式

public class Test01 {
    public static void main(String[] args) {

        new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                System.out.println("MyThread run");
            }
        }).start();
        run();
    }
    public static void run(){
        for (int i = 0; i < 5; i++) {
            System.out.println("Main run");
        }
    }
}
JDK 5.0新增:实现Callable接口

为啥子又要新增这样一个接口呢?

可能细心的小伙伴已经发现了,前面两种方式的返回值都是void,他们重写的run方法均不能直接返回结果。因此,不适合需要返回线程执行结果的业务场景。

执行步骤:

  1. 定义类实现Callable接口,重写call方法,封装要做的事情。
  2. 用FutureTask把Callable对象封装成线程任务对象。
  3. 把线程任务对象交给Thread处理。
  4. 调用Thread的start方法启动线程,执行任务
  5. 线程执行完毕后、通过FutureTask的get方法去获取任务执行的结果。

不错,在方法二的基础上又套了一层。

/**
 1、定义一个任务类 实现Callable接口  应该申明线程任务执行完毕后的结果的数据类型
 */
class MyCallable implements Callable<String>{
    private int n;
    public MyCallable(int n) {
        this.n = n;
    }

    /**
     2、重写call方法(任务方法)
     */
    @Override
    public String call() throws Exception {
        int sum = 0;
        for (int i = 1; i <= n ; i++) {
            sum += i;
        }
        return "子线程执行的结果是:" + sum;
    }
}

public class ThreadDemo3 {
    public static void main(String[] args) {
        // 3、创建Callable任务对象
        Callable<String> call = new MyCallable(100);
        // 4、把Callable任务对象 交给 FutureTask 对象
        //  FutureTask对象的作用1: 是Runnable的对象(实现了Runnable接口),可以交给Thread了
        //  FutureTask对象的作用2: 可以在线程执行完毕之后通过调用其get方法得到线程执行完成的结果
        FutureTask<String> f1 = new FutureTask<>(call);
        // 5、交给线程处理
        Thread t1 = new Thread(f1);
        // 6、启动线程
        t1.start();


        Callable<String> call2 = new MyCallable(200);
        FutureTask<String> f2 = new FutureTask<>(call2);
        Thread t2 = new Thread(f2);
        t2.start();

        try {
            // 如果f1任务没有执行完毕,这里的代码会等待,直到线程1跑完才提取结果。
            String rs1 = f1.get();
            System.out.println("第一个结果:" + rs1);
        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            // 如果f2任务没有执行完毕,这里的代码会等待,直到线程2跑完才提取结果。
            String rs2 = f2.get();
            System.out.println("第二个结果:" + rs2);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

底层Callable接口:Callable接口不能直接交给Thread

@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

底层FutureTask类:FutureTask实现了RunnableFuture接口,RunnableFuture接口继承了Runnable接口,所以可以交给Thread

public class FutureTask<V> implements RunnableFuture<V> {
    ...
}
public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}

FutureTask对象的作用

  1. 是Runnable的对象(实现了Runnable接口),可以交给Thread了
  2. 可以在线程执行完毕之后通过调用其get方法得到线程执行完成的结果

2.jpg

线程池方式创建

线程和数据库连接这些资源都是非常宝贵的资源。那么每次需要的时候创建,不需要的时候销
毁,是非常浪费资源的。那么我们就可以使用缓存的策略,也就是使用线程池.

因为线程池这块内容特别多,所以将在这篇文章后续统一讲述,目前知道还可以通过线程池创建线程便可。

多线程所带来的问题:线程安全问题

线程安全问题:多个线程同时操作同一个共享资源的时候可能会出现业务安全问题,称为线程安全问题

记得小时候看喜羊羊与灰太狼,里面有一个片段是,羊补桥,狼拆桥,双方同时进行,很专注,结果桥怎么都补不好,也拆不完。把羊和狼看作两个线程,桥看作共享资源,这就是一个线程安全问题。

emmm,可能不是很好理解。再举一个经典案例:两个人同时对一个账户进行取钱操作

  1. 判断余额是否大于0
  2. 取钱100元(假设账户里只有100元)
  3. 更改余额
    假设执行流程为:Person1(1)->Person2(1)->Person1(2)->Person1(3)此时余额为0元->Person2(2)->Person2(3)此时余额为-100元

综上:当多个线程同时访问同一个共享资源且存在修改该资源时会导致线程安全问题

那么如何解决这个问题呢

让多个线程实现先后依次访问共享资源,这样就解决了安全问题

如何实现先后依次访问共享资源?

加锁,把共享资源进行上锁,每次只能一个线程进入访问完毕以后解锁,然后其他线程才能进来。

关于锁的知识也很庞大,将在另外一篇博客中记载。

常见方法

sleep

sleep 方法属于 Thread 类中方法,表示让一个线程进入睡眠状态,等待一定的时
间之后,自动醒来进入到可运行状态,不会马上进入运行状态,因为线程调度机制恢复线程
的运行也需要时间.
一个线程对象调用了 sleep 方法之后,并不会释放他所持有的所有对象锁,所以也就不会影响其他进程对象的运行。
但在 sleep 的过程中过程中有可能被其他对象调用它的 interrupt(),产生 InterruptedException 异常,如果你的程序不捕获这个异常,线程就会异常终止,进入 TERMINATED 状态,如果你的程序捕获了这个异常,那么程序就会继续执行 catch 语句块(可能还有 finally 语句块)以及以后的代码。
注意 sleep()方法是一个静态方法,也就是说他只对当前对象有效,通过 t.sleep()让 t
对象进入 sleep,这样的做法是错误的,它只会是使当前线程被 sleep 而不是 t 线程

wait

wait 是 Object 类的方法,对此对象调用 wait 方法导致本线程放弃对象锁,进入等待
此对象的等待锁定池,只有针对此对象发出 notify 方法(或 notifyAll)后本线程才进入对象
锁定池准备获得对象锁进入运行状态。

sleep和wait比较
  1. 这两个方法来自不同的类分别是 Thread 和 Object
  2. 最主要是 sleep 方法没有释放锁,而 wait 方法释放了锁,使得其他线程可以使用同
    步控制块或者方法。
  3. wait,notify 和 notifyAll 只能在同步控制方法或者同步控制块里面使用,而 sleep 可
    以在任何地方使用(使用范围)
  4. sleep 必须捕获异常,而 wait,notify 和 notifyAll 不需要捕获异常
notify

notify 是 Object 类的方法,notify 方法只唤醒一个等待(对象的)线程并使该线程开始执行。所以如果有多个线程等待一个对象,这个方法只会唤醒其中一个线程,选择哪个线程取决于操作系统对多线程管理的实现。

notifyAll

notifyAll 是 Object 类的方法,它会唤醒所有等待(对象的)线程,尽管哪一个线程将会第一个处理取决于操作系统的实现

为什么wait和notify方法要在同步块中调用

wait()方法强制当前线程释放对象锁。这意味着在调用某对象的wait()方法之前,当前线程必须已经
获得该对象的锁。因此,线程必须在某个对象的同步方法或同步代码块中才能调用该对象的wait()方
法。
在调用对象的notify()和notifyAll()方法之前,调用线程必须已经得到该对象的锁。因此,必须在某
个对象的同步方法或同步代码块中才能调用该对象的notify()或notifyAll()方法。

为什么wait, notify 和 notifyAll这些方法不在thread类里面

JAVA提供的锁是对象级的而不是线程级的

yield

yield()方法是停止当前线程,让同等优先权的线程或更高优先级的线程有执行的机会。
如果没有的话,那么 yield()方法将不会起作用,并且由可执行状态后马上又被执行

join

join 方法是用于在某一个线程的执行过程中调用另一个线程执行,等到被调用的线程执
行结束后,再继续执行当前线程。

有三个线程T1,T2,T3,如何保证顺序执行

在多线程中有多种方法让线程按特定顺序执行,你可以用线程类的join()方法在一个线程中启动另一
个线程,另外一个线程完成该线程继续执行。T3调用T2,T2调用T1,这样T1就会先完成而T3最后完成。

中断线程

(1)使用退出标志,使线程正常退出,也就是当 run 方法完成后线程终止。
(2)通过 return 退出 run 方法
(3)通过对有些状态中断抛异常退出 thread.interrupt() 中断。
(4)使用 stop 方法强行终止线程(过期)

线程池

什么是线程池

线程池就是一个可以复用线程的技术。

为什么要使用线程池?

如果用户每发起一个请求,后台就创建一个新线程来处理,下次新任务来了又要创建新线程,而创建新线程的开销是很大的,这样会严重影响系统的性能。

举个现实生活中的案例:服务员服务客户,假设每来一个客人我就新招一个服务员,那就太亏了。

  1. 降低资源消耗。 通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
  2. 提高响应速度。 当任务到达时,任务可以不需要的等到线程创建就能立即执行。
  3. 提高线程的可管理性。 线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。

谁代表线程池?

JDK 5.0起提供了代表线程池的接口:ExecutorService

如何得到线程池对象?

  • 方式一:使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象
  • 方式二:使用Executors(线程池的工具类)调用方法返回不同特点的线程池对象
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java多线程 的相关文章

  • 太酷了,一款开源的轻量文件快递柜,像拿快递一样取文件!

    很多时候 xff0c 我们都想将一些文件或文本传送给别人 xff0c 或者跨端传递一些信息 xff0c 但是我们又不想为了分享 xff0c 而去下载一些七里八里的软件 xff0c 这时候 xff0c 我们就可以使用口令传送箱 xff0c 像
  • 大型 SaaS 系统的数据权限就应该这么设计

    toB 的系统 xff0c 除了普通的权限管理之外 xff0c 往往还需要数据范围权限 本文介绍一种 xff0c 简单的易实现的 Saas 多租户数据范围权限系统的简单设计与实现 权限的概述 我们一般说权限的时候是在说 功能权限和数据权限
  • 一款基于 Spring Cloud 开源的医疗信息系统

    今天给大家介绍一个医院信息系统开源项目 xff0c 相对比较完整 xff0c 采用的技术栈是 Spring cloud和Spring boot 2 x xff0c 比较主流 xff0c 正在做这方面系统的童鞋们可以参考一下 xff01 主要
  • Python 读取文件四种姿势:实例详解,从此读取文件更得心应手

    Python文件读取的四种方式如下 xff1a 1 逐行读取文件内容 逐行读取文件内容可以使用 for 循环和文件句柄对象 xff0c 如下所示 xff1a span class token keyword with span span c
  • 神技—终端显示Linux系统信息

    终端显示系统信息 准备工作 neofetch下载 xff08 Windows下zip xff0c Linux下tar gz xff09 下载地址 xff1a Netfetch Latest Release 解压安装 span class t
  • selenium中元素定位——css高级用法

    1 css简介 css xff08 Cascading style sheets xff09 层叠样式表 是一种用来表现HTML或者XML文档样式的计算机语言 css的规则主要由两部分构成 xff1a 选择器以及一条以及多条的声明 css选
  • Linux-交叉编译(常用工具的配置)

    交叉编译 编辑代码 gt 编译代码 gt 运行及调试代码 交叉编译也是一种编译 xff0c 也是把一种语言 源代码 翻译成另外一种语言 目标代码 在PC上面 xff0c 编译环境 就是你写代码和编译代码的那个机器环境 和 运行环境 运行你代
  • [转]使用wget命令下载Google drive上的文件

    转载说明 原文地址https blog csdn net Mao Jonah article details 88372086 感谢原作者分享 如有侵权 xff0c 请联系我删除 谢谢 xff01 此处的文件是指公开的文件 xff0c 不需
  • 非常实用的CSS命名(快速查找)

    css命名一直是让很多人感觉头疼的一件事 xff0c 参考网上的资料 xff0c 总结了一些常用的命名方法 xff0c 可以在用的时候方便查找 希望能给大家一些帮助 xff0c 不足之处也欢迎指正 xff01 xff01 xff01 常用的
  • systemctl管理脚本以及进程锁

    一 systemctl介绍 systemctl脚本存放在 xff1a usr lib systemd xff0c 有系统 xff08 system xff09 和用户 xff08 user xff09 之分 1 usr lib system
  • Windows10安装Terminal终端美化优化Linux的Ubuntu20.04子系统换字体背景换阿里云国内源

    这是一期美化优化子系统的教程 xff01 可以更替换字体和自己喜欢的背景 美化配置文件链接 xff1a https pan baidu com s 1kmmoKnOAON6SsCHL3xKoWw 提取码 xff1a aeyz 这文件是来自b
  • Spring的理解 入门

    Spring框架 控制反转 xff08 IOC xff09 1 Spring框架概述 1 1 什么是Spring Spring是一个开源框架 xff0c Spring是于2003 年兴起的一个轻量级的Java 开发框架 xff0c 由Rod
  • UI自动化之css定位语法-常用

    目录 元素定位方法选用顺序css定位与xpath定位比较定位元素的注意事项css选择器 元素定位方法选用顺序 优先级最高 xff1a ID优先级其次 xff1a name优先级再次 xff1a CSS selector优先级再次 xff1a
  • 这几本游戏开发书籍推荐给为未来的游戏工程师

    想当年 xff0c 我也是一名想做游戏开发的程序员 xff0c 大学的时候照葫芦画瓢做了一个半成品的 炉石传说 一度让我以为我将来会成为一名游戏开发工程师 xff0c 可惜后来我被C 43 43 的学习成本给全退了 xff0c 于是乎和游戏
  • Linux系统【Ubuntu】开机自启脚本及配置

    Linux系统 Ubuntu 开机自启脚本及配置 1 使用vim命令在 96 etc init d 96 目录下新建一个xx sh xff0c 文件名可自定义 xff0c 以test sh为例2 保存成功以后 xff0c 设置文本权限 xf
  • 电力电子技术笔记-逆变电路

    逆变的概念 逆变 与整流相对应 xff0c 直流电变成交流电 交流侧接电网 xff0c 为有源逆变 交流侧接负载 xff0c 为无源逆变 逆变与变频 变频电路 xff1a 分为交 交变频和交 直 交变频两种 交 直 交变频由交 直变换 xf
  • 短视频如何靠文案走红?盘点3个热门文案技巧

    很多短视频运营者常常都会忽略文案 xff0c 认为视频内容才是最重要的 xff0c 文案只是辅助 xff0c 但其实 xff0c 文案作为内容的逻辑支撑 xff0c 是短视频的点睛之笔 可以说 xff0c 一个爆款短视频 xff0c 绝对少
  • 短视频如何创作?掌握这些技巧,可以让你的短视频更火。

    现在短视频越来越受到大众的喜爱 xff0c 大概现在每个人坐车休假吃饭都在拿着手机刷着短视频 xff0c 可见现在短视频对于现在的人来说还是挺普遍的 xff0c 那么很多人都想从事短视频行业应该如何去进行创作呢 xff0c 下面就和大家分享
  • 短视频如何写爆款文案?爆款短视频文案技巧分享

    现在短视频越来越火热 xff0c 但是在短视频创作当中 xff0c 第一注重的就是视频 xff0c 文案是搭配辅助 xff0c 如果你的视频是走的内容风格 xff0c 那么文案对于你的短视频账号来说也是非常重要的 xff0c 要吸人眼球 x
  • OpenVINO 从yml处提取model下载链接,以mobile-ssd为例

    背景介绍 xff1a 最近需要下载公开模型 xff0c 无法从intel OpenVINO官方模型下载脚本中下载 报告ConnectionResetError Errno 104 Connection reset by peer xff0c

随机推荐

  • 短视频剪辑怎么做?4步教你快速入门

    最近看到很多小伙伴在问 xff0c 做短视频自媒体需要具备哪些技能 xff1f 要准备什么工具 xff1f 今天就给大家盘点一下 xff0c 短视频剪辑怎么做 xff0c 怎样才能快速入门 xff1a 01 剪辑软件 入门级别 xff1a
  • 短视频脚本怎么写?6个套路

    做短视频的基础就是脚本 xff0c 脚本是创作的基石 xff0c 是贯穿这个视频始末的逻辑 那么 xff0c 短视频脚本怎么做呢 xff1f 其实 xff0c 在拍摄脚本里面 xff0c 我们可以把所有的东西拆分为以下 6 个要素 xff1
  • 手机剪辑视频教程,初学者也能学会,上手快

    在过去的推文中 xff0c 和大家无数次的分享过剪映 xff0c 这是一个手机上就可以轻松实现视频剪辑的工具 xff0c 操作简单 xff0c 快速上手 对于想做短视频 xff0c 但是没有电脑的小伙伴 xff0c 如果你会用剪映 xff0
  • 推荐几个免费且高质量无版权的视频素材网站,记得收藏

    今天这篇文章给大家分享视频素材网站 xff0c 希望对大家有帮助 1 Coverr 第一个网站是Coverr Coverr是一个高质量的无版权视频素材下载网站 xff0c 有分类 xff0c 可以英文搜索 这个网站的视频素材质量还是很高的
  • 如何创作出优质的短视频文案?

    在短视频平台上进行创作 xff0c 视频才是重心点 xff0c 文案只不过是绿叶的辅助作用 xff0c 但常刷视频的小伙伴不难发现 xff0c 其实很多时候一句优质文案就可以把一条短视频推上热门 下面就和大家讲讲如何写出优质的文案 xff1
  • 短视频文案怎么吸引人,这几个技巧助你成为文案高手

    一 xff0e 人物状态 43 情感宣泄 61 情感共鸣 想要自己的视频上热门 xff0c 一定要和粉丝产生情感共鸣 xff0c 这样才能促使粉丝点赞 评论 转发 下面这个视频中的文案标题 xff1a 今天给外婆寄生活费回去 xff0c 电
  • 自媒体账号如何注册申请

    如何利用自媒体挣取到人生第一桶金 xff0c 建议大家可以从以下几个方面入手 一 申请自媒体账号 申请自媒体账号需要的材料 xff1a 身份证 xff0c 手机号 xff0c 辅助材料 xff1a 微信公众号或者博客写过文章的都可以 如果实
  • 自媒体人必备,5个免费找短视频素材的网站,赶紧收藏

    大家都知道做自媒体贵在坚持 xff0c 刚开始的时候你会发现还挺容易的 xff0c 但是到后面你会发现不知道发什么内容 xff0c 这时候可以用一些外部的素材来进行创作 xff0c 今天呢 xff0c 小易就给大家分享5个找视频素材的网站
  • 自媒体怎么做?5个操作步骤,普通人也可以做

    根据调查显示 xff0c 目前大家最爱做的副业就是自媒体 每天花1 2小时的时间 xff0c 不用才艺和露脸 xff0c 每天收入200左右 xff0c 比上班的工资还高 xff0c 操作非常的简单 小易整理了5个自媒体新手入门的操作步骤
  • 超好用的4个短视频素材下载网站,快收藏下来

    做过短视频运营的都知道 xff0c 最难的就是找素材 xff0c 在保证素材不侵权的情况下 xff0c 还有找高质量的内容 xff0c 真的很不容易 xff0c 很多人在这一步就已经头秃了 因此 xff0c 今天给大家安利一些超级好用的短视
  • [转] CMake入门

    转载说明 文章转自网络 xff0c 版权归原作者所有 xff0c 原文链接 https www hahack com codes cmake 特别感谢发哥 写代码的篮球痴 分享 文章目录 什么是 CMake 入门案例 xff1a 单个源文件
  • 抖音自媒体平台上最容易上热门的7大领域,你知道吗?

    抖音覆盖的内容领域日益广泛 xff0c 因此 xff0c 运营者在入驻抖音平台的时候不能过于草率 xff0c 不能单纯地根据个人偏好来确定账号的运营方向 本文将主要介绍在抖音平台上最容易上热门的7大领域 xff0c 以此来帮助运营者更好地进
  • 自媒体如何打造爆款呢,应该怎样掌握热点信息

    为什么优质的自媒体博主每天都在打造爆款 xff0c 无论是写文章还是拍视频 xff0c 他们的浏览量总位居前列 主要原因是因为平台推荐 xff1f 粉丝用户庞大 xff1f 这只是一部分原因 xff0c 能让他们从小V转变成大V的主要原因
  • 自媒体账号如何快速涨粉打造爆款,快来get这份运营技巧

    一 账号内容 在注册账号之后 xff0c 我们就要开始构思我们要发什么样的视频 xff0c 要知道我们想要将一个账号做好 xff0c 肯定不是像朋友圈一样 xff0c 今天发个日常 xff0c 明天发个自拍 xff0c 这样发布的作品会比较
  • FSK和GFSK

    1 FSK频移键控 频移键控 xff0c 英文缩写FSK 正弦振荡的频率在一组离散值间改变的角度调制 xff0c 其中每一离散值表示时间离散调制信号的一种特征状态 频移键控是利用两个不同频率F1和F2的振荡源来代表信号1和0 用数字信号的1
  • 多图详解!10大高性能开发核心技术

    程序员经常要面临的一个问题就是 xff1a 如何提高程序性能 xff1f 这篇文章 xff0c 我们循序渐进 xff0c 从内存 磁盘I O 网络I O CPU 缓存 架构 算法等多层次递进 xff0c 串联起高性能开发十大必须掌握的核心技
  • Mac系统中 用Virtualbox搭建CentOS虚拟机 鼠标光标占用、乱飞问题

    问题1 xff1a 我本人用的是MacBook Air xff0c 控制VirtualBox搭建 CentOS 7 的虚拟机时 xff0c 首先遇到了占用鼠标的问题 xff0c 如下图 看起来只需要点击 HostKey xff1a Righ
  • yum 仓库 (本地)

    首先要进入到 34 etc yum repos d 34 目录中 xff08 因为该目录存放着yum仓库的配置文件 xff09 cd etc yum repos d 使用vim或者vi编辑器创建一个名为local repo的新配置文件 xf
  • 噪声是什么?

    1 噪声的概念 日常我们说的噪声是 除了我想听到的声音 以外的声音 xff0c 就是噪声 比如我想听A君讲话 xff0c 但是B君和C君在旁边喋喋不休 xff0c 他们俩说的话是 我不想听到的声音 xff0c 那么他们两个的声音就是噪声 而
  • java多线程

    Java多线程并发 什么是多线程 线程 xff1a 程序内部的一条执行路径 xff08 比如说我们之前学的main方法就是一条单独的执行路线 xff09 单线程 xff1a 程序中如果只有一条执行路径 xff0c 那么这个程序就是单线程的程