【JavaEE】Java中的多线程 (Thread类)

这篇具有很好参考价值的文章主要介绍了【JavaEE】Java中的多线程 (Thread类)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

作者主页:paper jie_博客

本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。

本文录入于《JavaEE》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造,将基础知识一网打尽,希望可以帮到读者们哦。

其他专栏:《MySQL》《C语言》《javaSE》《数据结构》等

内容分享:本期会对JavaEE中一个关于多线程的重要类Thread进行分享~

目录

什么是Thread

创建线程

继承Thread类

实现Runnable接口

匿名内部类创建Thread子类对象

匿名内部类创建Runnable子类对象

lambda表达式创建子类对象

Thread类的方法与常见属性

构造方法

常见属性

常用方法

启动线程 - start()

中断线程 

引入标记

interrupt()

异常的原因

等待程序 - join()

获取当前线程引用 - currentThread()


什么是Thread

Thread类是在Java标准库中的,它可以视为是对操作系统提供的API进一步的抽象与封装. 一个Thread实例对象我们可以认为是一个线程.

创建线程

继承Thread类

这里需要继Thread类来创建一个线程类. 因为这里要重写run方法.里面就是这个线程需要执行的逻辑.

然后还需要创建它的实例,这样一个线程才算创建出来了. 最后需要调用start方法启动线程.

class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("hello Thread");

    }
}
public class ThreadDemo1 {
    public static void main(String[] args) {
        Thread t = new MyThread();
        t.start();
        System.out.println("hello main");
         
    }
}

实现Runnable接口

创建Thread实例,调用Thread构造方法时将Runnable对象作为参数.

class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("线程运行代码");
    }
}
public class ThreadDemo2 {
    public static void main(String[] args) {
        Thread t = new Thread(new MyRunnable());
        t.start();
        System.out.println("hell main");

    }
}

匿名内部类创建Thread子类对象

这里后面是Thread类的匿名子类.

public class ThreadDemo3 {
    public static void main(String[] args) {
        Thread t = new Thread("这是我"){
            @Override
            public void run() {
                System.out.println("这是匿名方法");
                while(true) {
                    System.out.println("heeh");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        };
        t.start();
    }
}

匿名内部类创建Runnable子类对象

public class ThreadDemo4 {
    public static void main(String[] args) {
        Thread t = new Thread(new Runnable(){
            @Override
            public void run() {
                System.out.println("匿名创建Runnable子类");
            }
        });
        t.start();
    }
}

lambda表达式创建子类对象

public class ThreadDemo5 {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            System.out.println("lambda表达式创建子类对象");
        });
        t.start();
    }
}

Thread类的方法与常见属性

构造方法

【JavaEE】Java中的多线程 (Thread类),# JavaEE,JAVA,java-ee,java

这里第三个和第四个可以重命名,这样可以更好的进行调试.

常见属性

【JavaEE】Java中的多线程 (Thread类),# JavaEE,JAVA,java-ee,java

ID是这个线程的唯一表示,不同的线程ID是不会重复的

名称一般就是调试的时候可以用到

状态表示一个线程当前所处的情况.一般有就绪状态和堵塞状态

优先级表示线程是不是更容易被调度

前台线程的运行会阻止进程的结束,后台线程的运行不会阻止进程的结束.一个进程的结束需要等所有前台线程执行完才会结束,不然就算是main线程执行完了也不会结束.我们创建的线程默认都是前台线程.

是否存活简单来说就是run方法是否执行完了. Java中Thread实例虽然代表的是多线程,但是它的生命周期和内核中创建出来的线程PCB的生命周期不是一样的.

【JavaEE】Java中的多线程 (Thread类),# JavaEE,JAVA,java-ee,java

此时虽然Thread实例对象有了,但是内核中线程还没创建,isAlive是false.只有在t.start()执行后内核中的线程才会创建出来,这时isAlive为true

【JavaEE】Java中的多线程 (Thread类),# JavaEE,JAVA,java-ee,java

当run方法执行完后,内核中的线程就销毁了,这时isAlive为false.

常用方法

启动线程 - start()

这里Thread实例对象虽然创建出来了,但是线程并未真正的启动.调用start()后才算真正的创建出了一个线程. 这里的start()才是在内核中创建出一个线程. 调用start()创建线程本质上就是调用系统的API来创建线程.

这里一个线程只能调用一次start(),再次使用start需要用另一个线程对象来调用.不然它会报出一个非法线程状态的异常.

public class ThreadDemo1 {
    public static void main(String[] args) {
        Thread thread = new Thread() {
            @Override
            public void run() {
                System.out.println("线程");
            }
        };
        thread.start();
        thread.start();
        System.out.println("hell main");
    }
}

【JavaEE】Java中的多线程 (Thread类),# JavaEE,JAVA,java-ee,java

中断线程 

中断一个线程就是提前让这个线程的run方法结束.常用的方法有两种:

1. 通过引入一个标记

2. 通过interrupt()方法

引入标记

这里通过flag这个标记来让run方法提前结束.当main线程执行到flag = true时,另一线程就会提前结束.

public class ThreadDemo2 {
    public static  boolean flag = false;
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                while(!flag) {
                    System.out.println("hell Thread");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        });
        thread.start();
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("终止这个线程");
        flag = true;
    }
}

这里注意,flag标识是不能在main方法内中,不能作为局部变量.虽然lambda匿名内部类可以通过变量捕捉访问到外面的局部变量.但是这个局部变量必须是不可变的,是final修饰的,这就和我们需要通过改变标记来终止线程发生冲突了,这就不可行.

【JavaEE】Java中的多线程 (Thread类),# JavaEE,JAVA,java-ee,java

必须是final是因为main方法和Thread都有自己的函数栈帧.他们生命周期不同.flag是在属于main的栈帧中,一但main执行完了,它的栈帧就会销毁,Thread再想使用就用不到了. 这里变量捕捉就是为了这个而诞生.它就是传参,本质上就是在需要的线程上将flag拷贝一份.为了保证flag的一致性就让它不能改变.

interrupt()

Thread里面自带一个标志位.我们可以通过方法来获取和改变这个标志位.

【JavaEE】Java中的多线程 (Thread类),# JavaEE,JAVA,java-ee,java

这里可以用Thread.interrupted()或者Thread.currentThread().isInterrupted()来获取内置的标志位.

interrupt()方法可以改变标志位.

这里使用了Thread.currentThread().isterrupted:

public class ThreadDemo3 {
    public static void main(String[] args) {
        Thread thread = new Thread(() -> {
            while(!Thread.currentThread().isInterrupted()) {
                System.out.println("hell Thread");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        thread.start();
        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("中断它");
        thread.interrupt();

    }
}

但运行代码后我们会发现问题:

【JavaEE】Java中的多线程 (Thread类),# JavaEE,JAVA,java-ee,java

这里会发现它会抛出一个中断异常,然后继续运行,并没有停下来.

异常的原因

这时因为这里interrupt()方法提前唤醒了sleep,这个时候sleep就会做两件事:

1. 抛出InterruptedExecption这个异常

2. 将内置标志位还原.

所有这会导致线程继续运行.

需要线程停下来,处理方法我们在catch里面加上break就可以了.

这里在catch中我们有三种处理方法:

1. 让线程立刻停下来

2. 让线程先运行一些代码再停下来

3. 让线程不停下来继续运行

 我们处理异常也有几种常见的方法:

【JavaEE】Java中的多线程 (Thread类),# JavaEE,JAVA,java-ee,java

等待程序 - join()

join方法可以调整线程执行的先后顺序.虽然说线程的调度执行是随机调度的.但这里join可以将线程进行堵塞从而影响到了线程的执行先后顺序.join所在的线程会发生堵塞,在调用join方法线程运行完后,这个线程的堵塞状态才会解除.

注意: 这里是调用join()的线程被等待先执行,join()所在的线程等待,后执行.

join()方法有三种:

【JavaEE】Java中的多线程 (Thread类),# JavaEE,JAVA,java-ee,java

第一种: 死等,需要等等待的线程执行完才会解除堵塞状态

第二种: 有时间的等待, 在一定时间内进行堵塞.超出时间范围就会解除堵塞状态

第三种:精确到微秒的有时间等待.

一般情况下,我们最常用的就是第二种情况:

public class ThreadDemo4 {
    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            while(true) {
                System.out.println("hell main");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        thread.start();
        thread.join();
        while(true) {
            System.out.println("hell ");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }

        }
    }
}

这段代码,就是main线程进入堵塞状态,等待Thread线程结束. 虽然说Thread这个线程这执行中可以和其他多个线程共同进行调度执行,但由于main线程一直在等待,就算Thread线程在CPU上进行了多次切换也不影响这个线程先执行完.

这里注意: 我们的interrupt方法可以将join线程提前唤醒.

获取当前线程引用 - currentThread()

 在使用类继承Thread创建线程方法我们可以用this直接引用这个对象.但是当使用lambda/匿名内部类/Runnable时this就不再指向Thread对象了.这时我们获取Thread对象引用就需要使用currentThread()方法了. 

【JavaEE】Java中的多线程 (Thread类),# JavaEE,JAVA,java-ee,java

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

休眠当前线程 - sleep() 

sleep可以将当前线程休眠一定时间,这个时间可以自己设定.但使用它需要抛出异常或者try- catch.这里休眠的时间因为线程调度的不可控,一般都会大于等于设定的时间.

它也有两种方法:

一般都是使用第一种,第二种是精确到微秒.

【JavaEE】Java中的多线程 (Thread类),# JavaEE,JAVA,java-ee,java文章来源地址https://www.toymoban.com/news/detail-753701.html

public class ThreadDemo8 {
    public static void main(String[] args) {
        Thread t = new Thread(() -> {
            try {
                Thread.sleep(1111);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("休眠1.111秒");
        });
        t.start();
    }
}

到了这里,关于【JavaEE】Java中的多线程 (Thread类)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • JAVA的多线程及并发

    继承 Thread 类; 实现 Runnable 接口; 实现 Callable 接口通过 FutureTask 包装器来创建 Thread 线程; 使 用 ExecutorService 、 Callable 、 Future 实 现 有 返 回 结 果 的多 线 程 ( 也 就 是 使 用 了 ExecutorService 来管理前面的三种方式)。 1、使用退出标志,使线程正常退出,也就是当 run

    2024年03月13日
    浏览(50)
  • 什么是Java的多线程?

    Java的多线程是指在同一时间内,一个程序中同时运行多个线程。每个线程都是一个独立的执行路径,可以独立地执行代码。Java中的多线程机制使得程序可以更高效地利用计算机的多核处理器和CPU时间,从而提高程序的性能和响应能力。 创建和使用Java多线程通常需要以下几个

    2024年02月02日
    浏览(31)
  • “深入理解Java的多线程编程“

    多线程编程是指在一个程序中同时运行多个线程,以提高程序的并发性和性能。Java是一门支持多线程编程的强大编程语言,提供了丰富的多线程相关类和接口。 在Java中,可以通过以下方式实现多线程编程: 继承Thread类:创建一个继承自Thread类的子类,并重写run()方法,在

    2024年02月13日
    浏览(67)
  • Java 线程池(Thread Pools)详解

    目录 1、线程池介绍 2、线程池执行原理 3、线程池中的阻塞队列 4、Java 线程池中的拒绝策略 5、Java 提供的创建线程池的方式 6、线程池的使用示例 7、ForkJoinPool 和 ThreadPool 的区别 1、线程池介绍          线程池是一种重用线程的机制 ,用于提高线程的利用率和管理线程的

    2024年02月05日
    浏览(40)
  • Java多线程---线程的创建(Thread类的基本使用)

    本文主要介绍Java多线程的相关知识, Thread的创建, 常用方法的介绍和使用, 线程状态等. 文章目录 前言 一. 线程和Thread类 1. 线程和Thread类 1.1 Thread类的构造方法 1.2 启用线程的相关方法 2. 创建第一个Java多线程程序 3. 使用Runnable对象创建线程 4. 使用内部类创建线程 5. 使用Lamba

    2024年02月03日
    浏览(40)
  • Java多线程 -Thread类的常用API

    Thread常用API说明 : Thread常用方法:获取线程名称getName()、设置名称setName()、获取当前线程对象currentThread()。 至于Thread类提供的诸如:yield、join、interrupt、不推荐的方法 stop 、守护线程、线程优先级等线程的控制方法,在开发中很少使用,这些方法会在高级篇以及后续需要用到

    2024年02月21日
    浏览(49)
  • JavaEE初阶:Java线程的状态

    目录 获取当前线程引用 休眠当前线程  线程的状态 1.NEW               2.TERMINATED  3.RUNNABLE 4.WAITING 5.TIMED_WAITING 6.BLOCKED 多线程的意义 单线程  多线程 这个方法返回当前线程的引用。但是我们会对static有疑惑,这其实是一个静态方法,更好的说法是这是一个 类方法, 调用这

    2024年02月11日
    浏览(42)
  • 深入浅出Java的多线程编程——第二篇

    目录 前情回顾 1. 中断一个线程 1.1 中断的API 1.2 小结 2. 等待一个线程  2.1 等待的API 3. 线程的状态 3.1 贯彻线程的所有状态 3.2 线程状态和状态转移的意义 4. 多线程带来的的风险-线程安全 (重点) 4.1 观察线程不安全 4.2 线程安全的概念 4.3 线程不安全的原因 4.3.1 修改共享数据

    2024年02月07日
    浏览(82)
  • 【Java练习题汇总】《第一行代码JAVA》多线程篇,汇总Java练习题——线程及多线程概念、Thread 类及 Runnable 接口、线程状态、synchronized同步操作...

    一、填空题 Java 多线程可以依靠________ 、________ 和________ 三种方式实现。 多个线程操作同一资源的时候需要注意________,依靠________ 实现,实现手段是:________ 和________,过多的使用,则会出现________ 问题。 Java 程序运行时,至少启动________ 个线程,分别是________ 和_

    2024年02月16日
    浏览(58)
  • Java 8并发集合:安全高效的多线程集合

    在多线程环境中,使用线程安全的数据结构非常重要,以避免竞态条件和数据不一致的问题。Java 8引入了一些并发集合类,提供了安全高效的多线程集合操作。本教程将介绍Java 8中的并发集合类,包括ConcurrentHashMap、ConcurrentLinkedQueue、ConcurrentSkipListSet和CopyOnWriteArrayList。 Conc

    2024年02月04日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包