Java特别篇--关于线程创建的三种方式的总结对比

文章目录

  • 一、常见3种创建线程的方式
    • (1)方式1:继承Thread类的方式
    • (2)方式2:实现Runnable接口的方式
    • (3)方式3:通过Callable和Future接口创建线程
  • 二、对比三种方式
    • (1)对比
    • (2)面试题

一、常见3种创建线程的方式

(1)方式1:继承Thread类的方式

☕线程的创建方式一:继承Thread类

<1> 创建步骤:

①创建一个类,继承Thread类。

②重写run方法。

③将需要由线程执行的具体动作写入run方法。

<2>运行步骤:

①创建线程类的对象。

②通过线程对象调用start方法启动线程。

第一种方式很简单,相信大家都会,详细博客在这里:
https://blog.csdn.net/m0_55746113/article/details/135708814?spm=1001.2014.3001.5502

🌱代码

package test2;

/**
 * ClassName: MyThread
 * Package: test2
 * Description:
 *
 * @Author 雨翼轻尘
 * @Create 2024/2/3 0003 17:28
 */
public class MyThreadMainTest {
    public static void main(String[] args) {
        //3.创建线程类的对象
        MyThread1 my1=new MyThread1();

        //4.通过线程对象调用start方法启动线程
        my1.start();
    }
}

//1.创建一个类,继承Thread类
class MyThread1 extends Thread{
    //2.重写run方法
    @Override
    public void run() {
        System.out.println("继承Thread类");
    }
}

🗃️注意

在start方法里面调用了start0(),如下:

image.png

start0是什么?

private native void start0();

注意看native关键字:

image.png

也就是说,start0方法的实现不是Java代码,是C或C++实现的,而C或C++在操作系统当中一般是用来操作驱动程序的。

驱动程序一般是由操作系统调用的,所以start0执行之后,此时程序的执行就交给了操作系统。操作系统决定让哪个线程的run方法执行。

start只是在这里保证线程的启动而已,启动以后的事情就脱离控制了,归操作系统管理。

(2)方式2:实现Runnable接口的方式

☕线程创建方式二:实现Runnable接口

<1> 创建步骤

①创建一个类,实现Runnable接口。

②重写run方法。

③将需要由线程执行的具体动作写入run方法。

<2> 运行步骤

①创建目标对象。

②通过Thread类的构造方法创建线程对象。

③通过线程对象调用start方法启动线程。

详细博客在这里:
https://blog.csdn.net/m0_55746113/article/details/135840102?spm=1001.2014.3001.5502

🗳️【说明】

这里再说详细一下Runnable接口实现的方式。

public class MyThreadMain {
    public static void main(String[] args) {
        //4.通过线程对象调用start方法来启动线程
        MyThread my1=new MyThread();

    }
}

//1.创建一个类,实现Runnable接口
class MyThread implements Runnable{
    //2.重写run方法
    @Override
    public void run() { //3.需要由线程执行的具体动作写入run方法
        System.out.println("实现Runnable接口的方式创建多线程");
    }
}

若按照方式一的步骤,最后一步应该是用对象调用start()方法,如下:

image.png

但是发现没有start()方法。

🎲为什么没有start()方法?

注意,start方法可以启动线程,但是这个start方法是Thread类的方法,而Runnable接口中没有start方法。

如下:

image.png

那么start方法不属于Runnable接口,当MyThread类实现了Runnable接口之后,自然也得不到start方法。

所以上面用实现类的对象调用start方法是不可行的。


🚗现在我们想调用start方法来启动线程,但是start方法是Thread类的。

那么想要调用start方法来调用,就需要使用Thread类的对象来调用。

现在只有MyThread的对象,所以需要将它变成Thread的对象。有什么关系呢?

我们写的MyThread类实现了Runnable接口,而Thread类也实现了Runnable接口。

现在去找Thread类的构造方法,如下:

public Thread(Runnable target) {
    this(null, target, "Thread-" + nextThreadNum(), 0);
}

注意看这个构造方法public Thread(Runnable target)的参数Runnable target,是Runnable接口。

当一个方法的参数是接口类型的时候,可以传递这个接口的子类

MyThread类是Runnable接口的子类,所以此时MyThread可以传递到参数上,那么就可以通过new Thread()来创建线程对象。

这时候会发现MyThread变成了Thread,通过构造方法变的。

image.png

此时Thread有了,Thread里面有start方法,所以接下来就可以使用th1来调用start方法。

如下:

image.png


🌱代码

package test2;

/**
 * ClassName: MyThreadMain
 * Package: test2
 * Description:
 *
 * @Author 雨翼轻尘
 * @Create 2024/2/3 0003 16:27
 */
public class MyThreadMain {
    public static void main(String[] args) {
        //4.创建线程要执行的目标对象(最终线程要执行的东西)
        MyThread my1=new MyThread();

        //Thread类的构造方法public Thread(Runnable target)
        //5.创建线程对象(Thread是Java提供的线程类,用线程类创建的对象就是线程对象)
        Thread th1=new Thread(my1);

        //6.通过线程对象调用start方法来启动线程
        th1.start();
    }
}

//1.创建一个类,实现Runnable接口
class MyThread implements Runnable{
    //2.重写run方法
    @Override
    public void run() { //3.需要由线程执行的具体动作写入run方法
        System.out.println("实现Runnable接口的方式创建多线程");
    }
}

(3)方式3:通过Callable和Future接口创建线程

🗳️认识几个接口和类

Callable接口:(只有一个方法call(),位于java.util.concurrent包)

@FunctionalInterface
public interface Callable<V> {
    V call() throws Exception;
}

call()方法有返回值V,这个返回值是实现接口的时候就决定的。

Future接口:(位于java.util.concurrent包)

有一个重要方法get()

③java.util.concurrent.FutureTask类:

public class FutureTask<V> implements RunnableFuture<V> 

RunnableFuture接口:

public interface RunnableFuture<V> extends Runnable, Future<V> {
    void run();
}

可以看到,FutureTask类实现了RunnableFuture接口,RunnableFuture接口继承了Runnable接口。

所以得出,FutureTask类实现了Runnable接口,那么FutureTask类就可以拿到Runnable的run方法

所以接下来创建线程类的时候,让它继承FutureTask类就可以拿到run方法。


☕线程创建方式三:通过Callable和Future接口创建线程

<1> 创建步骤

①创建一个类,实现Callable接口。

②重写call()方法。

③将需要由线程执行的具体动作写入call()方法。(可以通过call方法得到线程最终的执行结果)

<2> 运行步骤

①创建目标对象。

②通过FutureTask类的构造方法public FutureTask(Callable<V> callable)封装目标对象成Runnable的子类对象。–>为了让Callable和Runnable产生关系

③通过Thread类的构造方法public Thread(Runnable target)创建线程对象。

④通过线程对象调用start方法启动线程。


🚗举例

1、创建一个类,实现Callable接口

//1.创建一个类,实现Callable接口
class MyThread2 implements Callable<Integer>{ //<>代表call方法的返回值
    @Override
    public Integer call() throws Exception {

        return null;
    }
}

注意在实现Callable的时候要给出这个东西:

image.png

方法的返回值就是这个线程运行结果值的类型。

2、重写call方法

比如打印输出100个数字。

//1.创建一个类,实现Callable接口
class MyThread2 implements Callable<Integer>{ //<>代表call方法的返回值
    @Override
    public Integer call() throws Exception {
        int i=1;    //因为最后要返回i,所以这里将i从for里面拿出来
        for (; i <=100 ; i++) {
            System.out.println(Thread.currentThread().getName()+":"+i);
        }
        return i;
    }
}

也可以用while来写:

//1.创建一个类,实现Callable接口
class MyThread2 implements Callable<Integer>{ //<>代表call方法的返回值
    //2.重写call方法
    @Override
    public Integer call() throws Exception {
        int i=1;    //因为最后要返回i,所以这里将i从for里面拿出来
        while(i<=100){
            System.out.println(Thread.currentThread().getName()+":"+i);
            i++;
        }
        return i;
    }
}

现在一个线程操作类就创建好了。

注意:

实现Callable接口的时候需要指定线程执行结果的返回值类型(如果不知道具体返回什么,就写Object也行)。

<>里面的东西决定了这个线程执行以后返回值结果类型。

3、创建目标对象

public class MyThreadMainTest2 {
    public static void main(String[] args) {
        //3.创建目标对象
        MyThread2 my1=new MyThread2();
    }
}

4、用FutureTask封装目标对象

FutureTask类里面有一个构造方法,可以将Callable封装为FutureTask

如下:

private Callable<V> callable;
public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }

FutureTask类实现了Runnable接口,如下:

image.png

所以,我们的类实现了Callable接口,就可以变成一个实现Runnable的类,然后再用Thread类的构造方法将它封装成线程对象。

调用构造方法 public FutureTask(Callable<V> callable),并将目标对象传入。

如下:

public class MyThreadMainTest2 {
    public static void main(String[] args) {
        //3.创建目标对象
        MyThread2 my1=new MyThread2();

        //4.用FutureTask封装目标对象(因为FutureTask实现了Runnable接口)
        FutureTask futureTask=new FutureTask(my1);  //调用构造方法 public FutureTask(Callable<V> callable)
    }
}

那么futureTask就能成为Runnable接口的子类了。

所以,接下来要成为Runnable接口的子类的话,需要通过Thread类的构造方法

5、创建线程对象

通过Thread类的构造方法public Thread(Runnable target)创建线程对象。

如下:

public class MyThreadMainTest2 {
    public static void main(String[] args) {
        //3.创建目标对象
        MyThread2 my1=new MyThread2();

        //4.用FutureTask封装目标对象(因为FutureTask实现了Runnable接口)
        FutureTask futureTask=new FutureTask(my1);  //调用FutureTask的构造方法 public FutureTask(Callable<V> callable)

        //5.创建线程对象
        Thread th1=new Thread(futureTask);  //通过Thread类的构造方法 public Thread(Runnable target)创建线程对象
    }
}

6、启动线程

通过线程对象调用start方法启动线程。

如下:

public class MyThreadMainTest2 {
    public static void main(String[] args) {
        //3.创建目标对象
        MyThread2 my1=new MyThread2();

        //4.用FutureTask封装目标对象(因为FutureTask实现了Runnable接口)
        FutureTask futureTask=new FutureTask(my1);  //调用FutureTask的构造方法 public FutureTask(Callable<V> callable)

        //5.创建线程对象
        Thread th1=new Thread(futureTask);  //通过Thread类的构造方法 public Thread(Runnable target)创建线程对象

        //6.通过线程对象调用start方法启动线程
        th1.start();
    }
}

🌱代码

package test2;

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

/**
 * ClassName: MyThreadMainTest2
 * Package: test2
 * Description:
 *
 * @Author 雨翼轻尘
 * @Create 2024/2/3 0003 18:23
 */
public class MyThreadMainTest2 {
    public static void main(String[] args) {
        //3.创建目标对象
        MyThread2 my1=new MyThread2();

        //4.用FutureTask封装目标对象(因为FutureTask实现了Runnable接口)
        FutureTask futureTask=new FutureTask(my1);  //调用FutureTask的构造方法 public FutureTask(Callable<V> callable)

        //5.创建线程对象
        Thread th1=new Thread(futureTask);  //通过Thread类的构造方法 public Thread(Runnable target)创建线程对象

        //6.通过线程对象调用start方法启动线程
        th1.start();
    }
}

//1.创建一个类,实现Callable接口
class MyThread2 implements Callable<Integer>{ //<>代表call方法的返回值
    //2.重写call方法
    @Override
    public Integer call() throws Exception {
        int i=1;    //因为最后要返回i,所以这里将i从for里面拿出来
        while(i<=100){
            System.out.println(Thread.currentThread().getName()+":"+i);
            i++;
        }
        return i;
    }
}

🔥补充

线程运行的时候可以对线程做的一些处理。

java.util.concurrent.FutureTask类:

  • public boolean cancel(boolean mayInterruptIfRunning) :是否取消正在执行的线程任务。
    • false为取消线程任务
  • public boolean isCancelled():判断是否是线程任务没有运行结束之前取消线程。
  • public boolean isDone():判断线程任务是否正常执行完毕。
  • public V get():得到线程任务的执行结果。

🌱代码

package test2;

import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

/**
 * ClassName: MyThreadMainTest2
 * Package: test2
 * Description:
 *
 * @Author 雨翼轻尘
 * @Create 2024/2/3 0003 18:23
 */
public class MyThreadMainTest2 {
    public static void main(String[] args) {
        //3.创建目标对象
        MyThread2 my3=new MyThread2();
        MyThread2 my4=new MyThread2();

        //4.用FutureTask封装目标对象(因为FutureTask实现了Runnable接口)
        FutureTask futureTask3=new FutureTask(my3);  //调用FutureTask的构造方法 public FutureTask(Callable<V> callable)
        FutureTask futureTask4=new FutureTask(my4);

        //5.创建线程对象
        Thread th3=new Thread(futureTask3);  //通过Thread类的构造方法 public Thread(Runnable target)创建线程对象
        Thread th4=new Thread(futureTask4);

        //6.通过线程对象调用start方法启动线程
        th3.start();
        th4.start();
    }
}

//1.创建一个类,实现Callable接口
class MyThread2 implements Callable<Integer>{ //<>代表call方法的返回值
    //2.重写call方法
    @Override
    public Integer call() throws Exception {
        int i=1;    //因为最后要返回i,所以这里将i从for里面拿出来
        while(i<=100){
            System.out.println(Thread.currentThread().getName()+":"+i);
            i++;
        }
        return i;
    }
}

🍺输出(部分)

image.png


【方法演示】

public boolean cancel(boolean mayInterruptIfRunning) :是否取消正在执行的线程任务。【false为取消线程任务】

现在让Thread-1取消执行:

image.png

再次输出:

image.png

public boolean isCancelled():判断是否是线程任务没有运行结束之前取消线程。

若没有取消线程:

image.png

输出:

image.png

现在取消Thread-1:

//是否取消正在执行的线程任务
futureTask4.cancel(false);

//判断是否是线程任务没有运行结束之前取消线程
System.out.println(futureTask4.isCancelled());

输出:

image.png

public boolean isDone():判断线程任务是否正常执行完毕。

比如:

//public boolean cancel(boolean mayInterruptIfRunning):是否取消正在执行的线程任务
futureTask4.cancel(false);

//public boolean isCancelled():判断是否是线程任务没有运行结束之前取消线程
System.out.println(futureTask4.isCancelled());

//public boolean isDone():判断线程任务是否正常执行完毕
System.out.println(futureTask4.isDone());

输出:(因为线程Thread-1取消了,所以执行完毕,输出true)

image.png

若线程没有执行完毕,就会输出false,如下:

image.png

public V get():得到线程任务的执行结果。

//public V get():得到线程任务的执行结果。
try {
    int res=(Integer) futureTask4.get();
    System.out.println("线程1运行结果为:"+res);
} catch (InterruptedException e) {
    e.printStackTrace();
} catch (ExecutionException e) {
    e.printStackTrace();
}

输出:

image.png


🌱整体代码

package test2;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
 * ClassName: MyThreadMainTest2
 * Package: test2
 * Description:
 *
 * @Author 雨翼轻尘
 * @Create 2024/2/3 0003 18:23
 */
public class MyThreadMainTest2 {
    public static void main(String[] args) {
        //3.创建目标对象
        MyThread2 my3=new MyThread2();
        MyThread2 my4=new MyThread2();

        //4.用FutureTask封装目标对象(因为FutureTask实现了Runnable接口)
        FutureTask futureTask3=new FutureTask(my3);  //调用FutureTask的构造方法 public FutureTask(Callable<V> callable)
        FutureTask futureTask4=new FutureTask(my4);

        //5.创建线程对象
        Thread th3=new Thread(futureTask3);  //通过Thread类的构造方法 public Thread(Runnable target)创建线程对象
        Thread th4=new Thread(futureTask4);

        //6.通过线程对象调用start方法启动线程
        th3.start();
        th4.start();

        //public boolean cancel(boolean mayInterruptIfRunning):是否取消正在执行的线程任务
        //futureTask4.cancel(false);

        //public boolean isCancelled():判断是否是线程任务没有运行结束之前取消线程
        System.out.println(futureTask4.isCancelled());

        //public boolean isDone():判断线程任务是否正常执行完毕
        System.out.println(futureTask4.isDone());

        //public V get():得到线程任务的执行结果。
        try {
            int res=(Integer) futureTask4.get();
            System.out.println("线程1运行结果为:"+res);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

}

//1.创建一个类,实现Callable接口
class MyThread2 implements Callable<Integer>{ //<>代表call方法的返回值
    //2.重写call方法
    @Override
    public Integer call() throws Exception {
        int i=1;    //因为最后要返回i,所以这里将i从for里面拿出来
        while(i<=100){
            System.out.println(Thread.currentThread().getName()+":"+i);
            i++;
        }
        return i;
    }
}

二、对比三种方式

(1)对比

🔥表格对比图

继承Thread类实现Runnable接口Callable和Future接口
1、创建类继承Thread类
2、重写run方法
1、创建新类实现Runnable接口
2、重写run方法
1、创建新类实现Callable接口
2、重写call方法
3、注意Callable接口的泛型类型
run方法没有返回值,不能声明抛出异常run方法没有返回值,不能声明抛出异常call方法有返回值,通过Future接口提供的get方法得到返回值,可以声明抛出异常
1、创建Thread类的子类对象【线程对象】
2、通过子类对象调用start方法启动线程
1、创建实现类Runnable接口的子类对象【目标对象】
2、通过Thread类的构造方法,关联目标对象,创建线程对象【Thread类的对象】
3、通过线程对象调用start方法启动线程
1、创建实现Callable接口的子类对象【目标对象】
2、通过Future接口的子类FutureTask将目标对象包装成Runnable接口的子类对象
3、通过Thread的构造方法,关联FutureTask包装成的Runnable接口的子类对象【Thread类的对象】
4、通过线程对象调用start方法启动线程
无法共享资源(和目标对象没有关系)可以共享资源可以共享资源
不考虑资源共享时考虑资源共享时考虑资源共享时,异步编程

(2)面试题

🎲若同时使用Thread的run和Runnable的run方法,会怎样?

先用继承Thread的方式:

new Thread(){
    @Override
    public void run() {
        System.out.println("I am Thread");
    }
}.start();

然后用实现Runnable接口的方式,将Runnable接口实现类的对象写入小括号:

image.png

🌱代码

package test2;

/**
 * ClassName: BothRunnableThread
 * Package: test2
 * Description:
 *
 * @Author 雨翼轻尘
 * @Create 2024/2/3 0003 12:09
 */
public class BothRunnableThread {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("I am Runnable");
            }
        }){
            @Override
            public void run() {
                System.out.println("I am Thread");
            }
        }.start();
    }
}

🍺输出

image.png

可以看到,执行的是Thread里面重写的run方法,并没有执行Runnable里面的run方法。

若将run方法进行重写之后,会将Thread原有的run方法给覆盖:

image.png

当原有的Thread中的run方法被覆盖之后,也就是那几行代码已经不见了。

就无法执行到Runnable的重写的run方法了。

☕总结

准确来说,创建线程的方式只有一种,那就是new Thread

实现线程的执行单元有2种方式:一种是继承Thread,一种是实现Runnable

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

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

相关文章

CUDA/TensorRT部署知识点

CUDA相关: 1、CUDA核函数嵌套核函数的用法多吗? 答:这种用法非常少,主要是因为启动一个kernel本身就有一定延迟,会造成执行的不连续性。 2、如下代码里的 grid/block 对应硬件上的 SM 的关系是什么? 答:首先需要理解grid/block是软件层的概念,而SM是硬件层的概念。所…

python脚本将照片按时间线整理

说明&#xff1a;有一次自己瞎折腾&#xff0c;然后把服务器相册搞崩了&#xff0c;后来做了备份同步给找了回来&#xff0c;但是相册的时间线全乱了&#xff0c;看起来非常难受。所以就想通过文件夹的形式把照片重新分类&#xff0c;分类后的结构如下(红色字体为文件夹)&#…

人生百相,不过熵增熵减

这篇博文由两个问题衍生而来&#xff0c;分别是&#xff1a;“为什么除法比加法困难”、“什么是生命进化的目的”。在阅读其他人的解读时&#xff0c;发现都关联到了一个概念&#xff0c;熵。觉得十分有意思&#xff0c;因此记录一下自己的遐想。 熵&#xff08;Entropy&#…

vulhub中spring的CVE-2022-22965漏洞复现

在JDK 9上运行的Spring MVC或Spring WebFlux应用程序可能存在通过数据绑定执行远程代码&#xff08;RCE&#xff09;的漏洞。 现在已知的利用方法要求应用程序以WAR部署的形式在Tomcat上运行&#xff0c;然而&#xff0c;该漏洞的性质更为普遍&#xff0c;可能有其他方法可以利…

docker安装-centos

Docker CE 支持 64 位版本 CentOS 7&#xff0c;并且要求内核版本不低于 3.10 卸载旧版本Docker sudo yum remove docker \ docker-common \ docker-selinux \ docker-engine使用yum安装 yum 更新到最新版本: sudo yum update执行以下命令安装依赖包&#xff1a; sudo yum…

【无刷电机】无感方波驱动方案

无感方波驱动方案 1.通过无感过零信号构造霍尔换相信号2.无刷硬件驱动方案3.无感方波控制程序框架3.1有感方波控制3.2无感方波控制3.3无感启动方案3.4无感速度闭环控制1.通过无感过零信号构造霍尔换相信号 实现无感方波控制有软件比较和硬件比较两种方案。 软件比较是通过ADC采…

张维迎《博弈与社会》威胁与承诺(3)承诺行为

承诺的作用 上一节&#xff0c;我们探讨了如何在求解博弈时把不可置信的威胁或许诺排除出去&#xff0c;从而对参与人的行为做出合理的预测。如前所述&#xff0c;其中一个隐含的前提条件是&#xff0c;参与人要具有理性共识。而理性共识是一个要求很高的条件&#xff0c;现实生…

基于Springboot的校园失物招领网站(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的校园失物招领网站&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构…

基于Springboot的兼职网(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的兼职网&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0…

Oracle喊你领取免费AI 助理级证书啦!

拿证秘籍如下&#xff1a; 1. 登录Oracle的考试中心网站&#xff1a;https://education.oracle.com/certification 2. 选择AI 助理级考试&#xff0c;考试代码&#xff1a;1Z0-1122-23&#xff0c;也可以点击这里直达 3. AI学习视频免费看&#xff0c;也可以选择不看 3.5 去…

【git 本地管理版本及与github合并】 Init Push Pull操作解决方案

文章目录 创建本地仓库&#xff0c;并与远程仓库链接更新本地仓库并使用Push推送到远程仓库 1. 几种基础命令介绍&#xff1a;2. git push操作流程 .gitignore删除本地仓库&#xff0c;断开本地与远程的链接设置用于提交commit的用户名&#xff0c;邮箱&#xff0c;以便githu…

自建服务器监控工具uptime kuma

web服务器使用 雨云 提供的2核2g 这里使用1panel的uptime kuma 首先&#xff0c;如果你使用雨云&#xff0c;那么可以直接省去安装1panel的烦恼 直接选择预装后&#xff0c;等待部署完成即可看到面板信息&#xff0c;进入面板&#xff0c;点击应用商店 在应用商店里找到upti…

安装配置Oracle 11g 、PLSQL及使用Navicat远程连接Oracle

目录 一、下载 二、安装 1.执行安装程序 2.配置安全更新 3.安装选项 4.系统类 5.网络安装选项 6.选择安装类型 7.选择产品语言 8.选择数据库版本 9.指定安装位置 10.选择配置类型 ​编辑11.指定数据库标识符 12.指定配置选项 13.电子邮箱 14.指定数据库存储…

Android学习之路(28) 进程保活组件的封装

前言 远古时代&#xff0c;出现过很多黑科技&#xff0c;比如MarsDaemon&#xff0c;使用双进程守护的方式进行保活&#xff0c;在当时可谓风光无限&#xff0c;可惜在8.0时代到来就被废弃了。 又比如后面出现的1像素Activity的保活方式&#xff0c;说他流氓一点不过分&#…

解决Android camera 录像中拍照帧率不足30fps

问题现象 camera录像中拍照&#xff0c;录出来的视频帧率为29.3fps&#xff0c;未达到30fps。 问题分析 这个场景相当于跑了previevediocapture&#xff0c;极其损耗性能。 当前场景CPU频率已处于最高。 抓取systrace分析。 1&#xff0c;分析掉帧直接原因 SinkNode存在大…

【Leetcode】第 383 场周赛

文章目录 100214. 边界上的蚂蚁题目思路代码结果 100204. 将单词恢复初始状态所需的最短时间 I题目思路代码结果 100189. 找出网格的区域平均强度题目思路代码结果 100203. 将单词恢复初始状态所需的最短时间 II题目思路代码结果 100214. 边界上的蚂蚁 题目 题目链接 给你一个…

容器和镜像

容器和镜像是现代软件开发和部署中重要的概念&#xff0c;它们通常与容器化技术&#xff08;如Docker&#xff09;相关联。以下是它们的基本定义和关系&#xff1a; 容器(Container): 容器是一种轻量级、可移植的运行环境&#xff0c;其中包含了应用程序及其依赖项&#xff08;…

《Python 网络爬虫简易速速上手小册》第5章:Python 数据存储与管理(2024 最新版)

文章目录 5.1 选择数据存储方案5.1.1 重点基础知识讲解5.1.2 重点案例&#xff1a;使用 SQLite 存储博客文章数据5.1.3 拓展案例 1&#xff1a;使用 MongoDB 存储社交媒体动态5.1.4 拓展案例 2&#xff1a;使用 Elasticsearch 存储和检索日志数据 5.2 数据清洗与预处理5.2.1 重…

小林Coding_操作系统_读书笔记

一、硬件结构 1. CPU是如何执行的 冯诺依曼模型&#xff1a;中央处理器&#xff08;CPU&#xff09;、内存、输入设备、输出设备、总线 CPU中&#xff1a;寄存器&#xff08;程序计数器、通用暂存器、指令暂存器&#xff09;&#xff0c;控制单元&#xff08;控制CPU工作&am…

ShardingSphere 5.x 系列【1】专栏导读

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Spring Boot 版本 3.1.0 本系列ShardingSphere 版本 5.4.0 源码地址&#xff1a;https://gitee.com/pearl-organization/study-sharding-sphere-demo 文章目录 1. 背景2. 简介3. 适用人群4. 环境…