首页 > 编程语言 >大家都说Java有三种创建线程的方式!并发编程中的惊天骗局!

大家都说Java有三种创建线程的方式!并发编程中的惊天骗局!

时间:2023-06-09 18:11:25浏览次数:46  
标签:Java Thread 创建 任务 线程 惊天 new public

在Java中,创建线程是一项非常重要的任务。线程是一种轻量级的子进程,可以并行执行,使得程序的执行效率得到提高。Java提供了多种方式来创建线程,但许多人都认为Java有三种创建线程的方式,它们分别是继承Thread类、实现Runnable接口和使用线程池。

但是,你们知道吗?其实在创建线程的过程中,除了上述描述的方法还有很多种方式可以选择哦。今天,我们就来揭开这个惊天秘密,一起来了解一下Java并发编程中创建线程的八股文。

一. 创建线程的方法:

1. 继承Thread类创建线程

这是最基本的创建线程的方式,我们可以通过继承Thread类来创建一个自定义的线程类,然后重写run()方法,实现线程的逻辑。

public class MyThread extends Thread {
    @Override
    public void run() {
        // 线程逻辑
    }
}

// 创建并启动线程
MyThread myThread = new MyThread();
myThread.start();

2. 实现Runnable接口创建线程

这是另一种常见的创建线程的方式,我们可以通过实现Runnable接口来创建一个自定义的线程类,然后将该类实例化并传递给Thread类的构造方法中,最后调用start()方法启动线程。

public class MyRunnable implements Runnable {

@Override

public void run() {

// 线程逻辑

}

}

// 创建并启动线程

MyRunnable myRunnable = new MyRunnable();

Thread thread = new Thread(myRunnable);

thread.start();

3. 实现Callable接口创建线程

Callable接口与Runnable接口类似,但是它可以返回一个结果并抛出异常。我们可以通过实现Callable接口来创建一个自定义的线程类,然后将该类实例化并传递给FutureTask类的构造方法中,最后调用start()方法启动线程。

public class MyCallable implements Callable {

@Override

public String call() throws Exception {

// 线程逻辑

return "result";

}

}

// 创建并启动线程

MyCallable myCallable = new MyCallable();

FutureTask futureTask = new FutureTask<>(myCallable);

Thread thread = new Thread(futureTask);

thread.start();

// 获取线程返回结果

String result = futureTask.get();

4. 使用线程池创建线程

线程池是一种重用线程的机制,可以减少线程创建和销毁的开销。我们可以通过Executors类提供的静态方法来创建不同类型的线程池,然后将任务提交给线程池执行。

ExecutorService executorService = Executors.newFixedThreadPool(10);

// 提交任务并执行

executorService.submit(new Runnable() {

@Override

public void run() {

// 线程逻辑

}

});

// 关闭线程池

executorService.shutdown();

5. 使用定时器创建线程

定时器可以用来定时执行某个任务。我们可以通过Timer类来创建一个定时器,然后将任务添加到定时器中执行。
请添加图片描述

6. 使用ScheduledExecutorService创建线程

ScheduledExecutorService是一种可以调度任务执行的线程池。我们可以通过它来创建一个定时任务,也可以创建一个周期性任务。

ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);

// 创建定时任务并执行
scheduledExecutorService.schedule(new Runnable() {
    @Override
    public void run() {
        // 线程逻辑
    }
}, 1, TimeUnit.SECONDS);

// 创建周期性任务并执行
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
    @Override
    public void run() {
        // 线程逻辑
    }
}, 1, 1, TimeUnit.SECONDS);

// 关闭线程池
scheduledExecutorService.shutdown();

7. 使用Fork/Join框架创建线程

Fork/Join框架是Java 7中引入的一种并行执行任务的机制。它可以将一个大任务拆分成多个小任务并行执行,最后将结果合并。

public class MyTask extends RecursiveTask {
    private int start;
    private int end;

    public MyTask(int start, int end) {
        this.start = start;
        this.end = end;
    }

    @Override
    protected Integer compute() {
        if (end - start <= 1000) {
            // 执行小任务
            return 0;
        } else {
            // 拆分大任务
            int mid = (start + end) / 2;
            MyTask leftTask = new MyTask(start, mid);
            MyTask rightTask = new MyTask(mid + 1, end);
            leftTask.fork();
            rightTask.fork();

            // 合并结果
            return leftTask.join() + rightTask.join();
        }
    }
}

// 创建并执行任务
ForkJoinPool forkJoinPool = new ForkJoinPool();
MyTask myTask = new MyTask(1, 10000);
int result = forkJoinPool.invoke(myTask);

8. 使用Semaphore创建线程

Semaphore是一种计数器,用来控制同时访问某个资源的线程数量。我们可以通过Semaphore来创建一个有限的线程池。

Semaphore semaphore = new Semaphore(10);

// 创建并执行任务
Runnable runnable = new Runnable() {
    @Override
    public void run() {
        try {
            semaphore.acquire();
            // 线程逻辑
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            semaphore.release();
        }
    }
};

for (int i = 0; i < 100; i++) {
    new Thread(runnable).start();
}

二. 线程和线程体的关系

说到线程大家都知道,它是一种重要的多任务处理机制。可以让我们同时执行多个任务,并且可以提高程序的效率。 上述也给大家带来了很多种创建线程的方式,但是说到这里,我发现经常有朋友问:线程体和线程是什么关系?其实,简单说:线程体就是是线程的具体执行代码。那么接下来就让我们具体来看看线程和线程体的关系吧!

1. 线程和线程体的关系

在Java中,线程和线程体是两个不同的概念。

线程是一条执行路径,线程体是线程的具体执行代码。 每个线程都有一个与之相关的线程体。线程体是实现了Runnable接口的类的实例。线程体可以是一个独立的类,也可以是一个内部类。线程创建之后,它的run()方法就会被调用,run()方法中的代码就是线程体的执行代码。

2. 案例说明

可能会有朋友觉得上述的解释过于书面化,那么如果通过生活实例来说明线程体和线程的关系的话,我们可以将线程理解成为一个人,线程体则是这个人所做的事情。

比如,在上班的路上,我们可以同时进行多个任务,比如听音乐、看书、发短信等等。这些任务就可以看做是这个人的线程体。线程就是这个人同时进行多个任务的机制。如果我们只有一个人,那么这个人必须先做完一个任务才能开始做下一个任务。这样就会浪费很多时间。但是如果我们有两个人,那么一个人可以看书,另一个人可以听音乐,这样就可以同时进行多个任务,提高了效率。

3. 代码案例

下面给大家带来一个:创建多个线程来同时执行多个任务的简单的代码案例,示例如下:

public class MyThread implements Runnable {
    private String taskName;

    public MyThread(String taskName) {
        this.taskName = taskName;
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(taskName + "执行了第" + (i + 1) + "次任务");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        MyThread thread1 = new MyThread("线程1");
        MyThread thread2 = new MyThread("线程2");
        Thread t1 = new Thread(thread1);
        Thread t2 = new Thread(thread2);
        t1.start();
        t2.start();
    }
}

在这个案例中,我们创建了两个线程,分别执行不同的任务。每个线程的线程体是MyThread类的run()方法。在run()方法中,每个线程会执行5次任务,并在每次任务之间暂停1秒钟。通过创建多个线程,我们可以同时执行多个任务,提高程序的效率。

4. 小结

通过上述介绍的Java线程和线程体的关系,大家应该都清楚了。线程是一种多任务处理机制,线程体是线程的具体执行代码。在Java中,我们可以通过创建多个线程来同时执行多个任务,提高程序的效率。希望上述可以帮助大家更好地理解Java中线程和线程体的概念哦。

三. 总结

现在大家都知道了在Java并发编程中,创建线程是一个非常重要的操作。

本文给大家介绍了八种不同的创建线程的方式,包括继承Thread类、实现Runnable接口、实现Callable接口、使用线程池、使用定时器、使用ScheduledExecutorService、使用Fork/Join框架和使用Semaphore。

每种方式都有各自的优缺点,我们需要根据实际情况选择合适的方式来创建线程。同时,我们还需要注意线程安全和性能等问题,确保程序的正确性和高效性。

在生活中,我们也可以找到很多与多线程编程相关的例子。比如,在厨房里做饭的时候,我们可以将不同的任务分配给不同的人来完成,比如一个人负责洗菜,一个人负责切菜,一个人负责烧菜等等。这样可以提高效率,也可以避免出现混乱和错误。同样,在程序中,我们也可以将不同的任务分配给不同的线程来完成,以提高程序的响应速度和吞吐量。因此,多线程编程是非常重要的,值得我们深入学习和掌握。希望能对大家有所帮助哦。


标签:Java,Thread,创建,任务,线程,惊天,new,public
From: https://www.cnblogs.com/qian-fen/p/17469944.html

相关文章

  • JavaScript 构造器模式:创建可重用的对象
    前言JavaScript是一种基于对象的语言,对象是JavaScript中最重要的概念之一。在JavaScript中,我们可以使用构造器模式来创建可重用的对象。本文将介绍JavaScript构造器模式的概念、用法和实例,并给出博客标题《JavaScript构造器模式:创建可重用的对象》。构造器模式构造器模......
  • Caused by: java.lang.ClassNotFoundException: com.alibaba.fastjson2.util.Wrap
    1.情景展示使用fastjson2,运行时报错:Causedby:java.lang.ClassNotFoundException:com.alibaba.fastjson2.util.Wrap2.具体分析出现这个问题,是因为pom.xml当中引用的有关fastjson的jar包冲突造成的。只要我们把冲突的jar包排除掉就可以了。3.解决方案在idea当中,使用插件......
  • Java 集合框架体系简介
    为什么要使用集合存储多个数据可以使用数组,但由于数组在内存中是连续存储的,所以会有一些限制。比如数组在创建时就要指定长度,即可以容纳的元素个数,且指定后无法更改;数组在创建时需要指定元素的类型,并且所有元素都必须是该类型或其子类;添加或删除数组中的元素需要创建一个新数组再......
  • 多线程与多进程
    多线程与多进程一,什么是进程,什么是线程?​ 进程:运行中的程序.每次我们执行一个程序,咱们的操作系统对自动的为这个程序准备一些必要的资源(例如,分配内存,创建一个能够执行的线程.)​ 线程:程序内,可以直接被CPU调度的执行过程.是操作系统能够进行运算调度的最......
  • java的接口和抽象类简单理解
    接口是定义了系统各模块应该遵守的标准。实现者对外提供哪些服务,调用者可以调用哪些服务以及如何调用服务。抽象类作为系统中各个子类的共同父类,所表现的是一种模板设计,只实现了最基础的共通功能,相当于一个中间产品,各个子类具体实现抽象方法。抽象类可以没有抽象方法,......
  • java8如何校验ssh-keygen生成的公私钥
    如果你的公私钥文件不是PEM格式的,而是其他格式,如OpenSSH格式(通常以`id_rsa`和`id_rsa.pub`命名),你可以使用Java的`JSch`库来验证它们的有效性。下面是一个示例代码,演示如何使用`JSch`库验证OpenSSH格式的公私钥对:首先,你需要在项目中引入JSch库的依赖。你可以使用Maven或手动下载并......
  • java不打印异常堆栈
    背景:生产环境抛异常,但却没有将堆栈信息输出到日志,只有简单的java.lang.NullPointerException错误信息。原因分析JVM在默认启动的时候会加上OmitStackTraceInFastThrow参数,含义是当大量抛出同样的异常的后,后面的异常输出将不打印堆栈。原因是打印堆栈的时候底层会调用到Throw......
  • 使用JAVA开发微信公众平台(一)——环境搭建与开发接入
    一、初始微信公众平台微信公众平台,即我们平时所说的“公众号”,曾用名“官方平台”、“媒体平台”,但最终命名为“公众平台”。从微信的命名我可以发现,公众平台不只是官方、媒体使用的平台,而是对所有公众都开放的统一平台。喜欢本文,请点击下方喜欢按钮呗!❤️微信公众平台地址:http......
  • Java面试题精华集-Java 工程师进阶知识完全扫盲
    在GitHub/Gitee编辑消息队列面试场景面试官:你好。候选人:你好。(面试官在你的简历上面看到了,呦,有个亮点,你在项目里用过MQ,比如说你用过ActiveMQ)面试官:你在系统里用过消息队列吗?(面试官在随和的语气中展开了面试)候选人:用过的(此时感觉没啥)面试官:那你说一下你们在项目里是......
  • 全网八股文面试高频题目--JAVA基础
    八股文--JAVA基础目录八股文--JAVA基础1.JDK、JRE、JVM有什么区别1.1Java为什么被称为平台无关性语言?2.常用数字类型的区别3.Float在JVM的表达方式及使用陷阱4.面向对象三个特性是什么4.1重载和重写的区别?4.2Java中是否可以重写一个private或者static方法?4.3构造方法有哪些......