锋盈数科-知识库 Logo
首页
软件开发
计算机基础
Hello Halo
新手必读
关于本知识库
登录 →
锋盈数科-知识库 Logo
首页 软件开发 计算机基础 Hello Halo 新手必读 关于本知识库
登录
  1. 首页
  2. 软件开发
  3. 初识Thread类与创建多线程的方法

初识Thread类与创建多线程的方法

0
  • 软件开发
  • 发布于 2024-09-19
  • 0 次阅读
黄健
黄健

目录


1.创建一个线程

2.start()方法与run()方法

3.查看线程

4.创建线程的各种方法

4.1实现Runnable接口

4.2使用匿名内部类

4.3使用匿名内部类,实现Runnable

4.4使用Lambda表达式



1.创建一个线程

Java操作线程最核心的类就是Thread类

创建线程有很多方法,下面我们写一个Mythread类继承 Thread 类重写run()方法来创建线程

package thread;
class MyThread extends Thread{
    public void run(){
        System.out.println("hello world!");
    }

}
public class ThreaDemo1 {
    public static void main(String[] args) {
        Thread t = new MyThread();
    }
}

这里的Thread类不需要import包,是因为这个类和String,StringBuffer这些类一样是在java.lang包中,已经自动导入了!

run()方法是重写了Thread类的run()方法,重写就是和父类方法名参数都相同,子类的方法通过动态绑定机制被调用

就像上面的:

Thread t = new MyThread();
t.run();

这里的t是父类的引用,调用的 run()仍然是子类的方法,本质上t还是指向子类对象

重载是同一个作用域,多个方法的方法名相同,参数个数或类型不同的方法

2.start()方法与run()方法

我们用t调用一个strat方法

public class ThreaDemo1 {
    public static void main(String[] args) {
        Thread t = new MyThread();
        t.start();
    }
}

这里的hello world和我们直接在打印出来的hello world是不同的!!!

这里的是由 t.start()创建了一个新的线程,然后由线程负责执行t.run(),打印出hello world!

t.start()创建新的线程时,调用了操作系统的API,通过操作系统内核创建新线程的PCB,并把要执行的指令交给这个PCB,当PCB被调度到CPU上执行的时候,就能执行到run()方法中的代码了

直接打印hello world时,java进程就只有一个线程(就是调用main方法的线程)也就是主线程

通过 t.start(),主线程调用了t.start(),t.start()创建出新的线程,新的线程调用t.run();

当run()方法执行完毕,新的的线程就自动销毁

创建线程归结到底还是要解决并发编程问题,我们来看一个并发的例子

class MyThread extends Thread{
    public void run(){
        while(true){
            System.out.println("hello world!");
            //休眠
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }

}
public class ThreaDemo1 {
    public static void main(String[] args) {
        Thread t = new MyThread();
        t.start();

        while(true){
            System.out.println("hello main!");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

这段代码并不是只执行到一个循环,死循环出不来了,而是交替执行的

这就是并发执行的效果,执行的顺序也是不确定的,主要原因是:操作系统调度线程的时候是"抢占式执行”,具体哪个线程先执行,哪个线程后执行,都是不确定的,取决于操作系统调度策略

虽然也是有优先级的,但是从应用程序方面来看到的效果是随机的,我们在程序上无法修改的

如果我们只执行t.run()会是什么情况呢?

结果

这里只执行了run方法,没有执行hellomain这里,是因为只有一个主线程是单线程工作的

不会交替执行,这就是单线程和多线程的差异

run()和start()的区别

run是线程里的方法,描述的是线程要执行的任务,但是线程还没有执行,只有调用start后,线程才会开始运行,调用后会申请线程并执行run方法,执行完后进入销毁线程阶段,也就是说strat才是真正创建了线程,并且线程是独立的执行流

3.查看线程

我们可以使用jdk自带的工具jconsole查看当前的java进程中的所有线程

这个工具一般路径:C:\Program Files\Java\jdk1.8.0_192\bin

双击打开运行会看到本地进程

接下来点击一下我们运行的程序的线程

点击线程

可以看到有很多线程

详细信息

其它的线程都是JVM自带的线程

注意:如果打开工具本地进程什么也没有,可以尝试用右键,管理员方式运行

new Thread 对象时,不创建线程,调用start才是创建PCB才有真实的线程

主线程调用就是start方法写到main方法中被调用

4.创建线程的各种方法

Java中创建线程的方法有很多种,上面使用的就是继承Thread类,重写run()方法的方法,下面了解一下其他三种方法

4.1实现Runnable接口

回顾:

抽象类和普通类的区别:抽象类不能实例化,不能直接new,必须有子类继承抽象类,然后抽象类中有抽象方法,抽象方法没有方法体,需要子类重写抽象方法

接口比抽象类更进一步,抽象类除抽象方法之外还有普通方法和属性,接口则是只有抽象方法

class MyRunnable implements Runnable{
    public void run(){
        System.out.println("hello thread!");
    }
}
public class ThreadDemo2 {
    public static void main(String[] args) {
        Runnable runnable = new MyRunnable();
        Thread t = new Thread(runnable);
        t.start();
    }
}

Runnable是描述任务,具体执行细节就是run()方法,任务还要交给线程来执行

使用Runnable接口达到了解耦合的目的,将线程和线程的任务分开,如果要修改代码,代码改动就比较小

4.2使用匿名内部类

public class ThreadDemo3 {
    public static void main(String[] args) {
        Thread t = new Thread(){
            @Override
            public void run() {
                System.out.println("hello world!");
            }
        };
                t.start();
    }
}

这里创建了一个Thread的子类,子类是匿名的,还创建了子类的实例,并且让t指向实例

4.3使用匿名内部类,实现Runnable

public class ThreadDemo4 {
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("hello world!!");
            }
        });
        t.start();
    }
}

写法和1本质相同,只不过把实现Runnable 任务交给匿名内部类的语法,此处是创建了一个类,实现Runnable,同时创建了实例 ,并且把实例传给Thread的构造方法(匿名内部类的创建的实例作为Thread的构造方法参数)

4.4使用Lambda表达式

这是比较简单的,推荐的写法

public class ThreadDemo5 {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            System.out.println("hello world!!");
        });
        t.start();
    }
}

把任务通过Lambda表达式来描述,直接把Lambda表达式传给Thread的构造方法

原文链接: https://blog.csdn.net/chenchenchencl/article/details/128106312

标签: #多线程 1 #软件开发 1171
相关文章

万字:支付“核心系统”详解 2024-11-02 15:33

专栏作者:隐墨星辰 \| 主编:陈天宇宙 这篇文章也尝试化繁为简,探寻支付系统的本质,讲清楚在线支付系统最核心的一些概念和设计理念。 虽然支付行业已经过了风头最劲的时光,但跨境支付仍然在蓬勃发展,每年依然有很多新人进入这个行业,这篇文章尝试为这些刚入行的新人提供一点帮助。 文章只介绍一些支付行业十几

资深支付架构师视角:实战从问题定义到代码落地的完整套路 2024-11-02 15:33

前言 今天从一个实际案例入手,介绍站在架构师的角度,如何识别并定义问题,提炼需求,技术方案选型,再到详细设计,最后利用AI的能力协助写出核心的代码,验证与调优。 解决问题存在一定的模式,也可以称之为框架,总结出自己的思考和解题框架,以后再碰到同类型的问题就可以如庖丁解牛一样容易。 很多年前,我写代码

Spring 实现 3 种异步接口 2024-10-18 09:07

大家好,我是苏三~ 如何处理比较耗时的接口? 这题我熟,直接上异步接口,使用 Callable、WebAsyncTask 和 DeferredResult、CompletableFuture等均可实现。 但这些方法有局限性,处理结果仅返回单个值。在某些场景下,如果需要接口异步处理的同时,还持续不断地

重学SpringBoot3-集成Redis(五)之布隆过滤器 2024-10-08 11:24

更多SpringBoot3内容请关注我的专栏:《SpringBoot3》 期待您的点赞👍收藏⭐评论✍ 重学SpringBoot3-集成Redis(五)之布隆过滤器 1. 什么是布隆过滤器? * 基本概念 适用场景 2. 使用 Redis 实现布隆过滤器 * 项目依赖 Redis 配置

设计模式第16讲——迭代器模式(Iterator) 2024-10-08 11:24

一、什么是迭代器模式 迭代器模式是一种行为型设计模式,它提供了一种统一的方式来访问集合对象中的元素,而不是暴露集合内部的表示方式。简单地说,就是将遍历集合的责任封装到一个单独的对象中,我们可以按照特定的方式访问集合中的元素。 二、角色组成 抽象迭代器(Iterator):定义了遍历聚合对象所需的方法

vue2路由和vue3路由区别及原理 2024-10-08 11:24

一、Vue2 与 Vue3 路由的区别 1. 创建路由实例方式的不同 Vue 2 中,通过 Vue.use() 注册路由插件,并通过 new VueRouter() 来创建路由实例。 import Vue from 'vue';import VueRouter from 'vue-router';i

目录

IT 外包服务商

  • 意见投递
  • zyf6619

软件开发应用

主菜单

  • 首页
  • 软件开发
  • 计算机基础
  • Hello Halo
  • 新手必读
  • 关于本知识库
Copyright © 2024 your company All Rights Reserved. Powered by Halo.