栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

多线程编程之Thread类的使用

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

多线程编程之Thread类的使用

文章目录

省Thread类的使用

 线程的创建

测试线程串行和并发执行的效率 start()方法与run()方法 线程的中断线程的等待 线程获取引用线程的休眠

若想在Java中进行多线程编程,我们不得不提到在Java标准库中,存在一个Thread类可以对线程进行一系列的操作
Thread类可以视为是java标准库提供的API.
创建好的Thrad实例,其实和操作系统中的线程是一一对应的关系,操作系统提供了一组关于线程的API(C语言风格),Java对这组APi进一步封装了一下,就变成了Thread类

省Thread类的使用  线程的创建
    创建子类,继承Thread
class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("hello thread");
    }
}
public class TestDemo1 {
    public static void main(String[] args) {
        Thread t = new MyThread();
        t.start();
    }
}

这里需要注意的start()方法,只有调用了这个方法,才是在系统创建了线程,在这之前系统是没有创建出线程的,下文我们会着重的去介绍start()方法,它与上列代码重写的run()方法有着区别

2.创建一个类,实现Runnable接口,在创建Runnable实例传给Thread实例

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

通过 Runnable来描述任务的内容
再进一步把描述好的任务传给Thread实例

3.使用匿名内部类(上两种版本的翻版)

关于匿名内部类的知识,博主也不是很了解,也没办法给大家讲解,大家可以点击下面的链接

匿名内部类

public class TestDemo3 {
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable(){
            @Override
            public void run() {
                System.out.println();
            }
        });
        thread.start();
    }
}
public class TestDemo4 {
    public static void main(String[] args) {
        Thread thread = new Thread(){
            @Override
            public void run() {
                System.out.println("love");
            }
        };
        thread.start();
    }
}
    lambda表达式
public class TestDemo5 {
    public static void main(String[] args) {
        Thread thread = new Thread(() ->{
            System.out.println("hello");
        });
        thread.start();
    }
}
测试线程串行和并发执行的效率

有两个整数变量,分别要对这两个整数变量自增十亿次
我们分别使用一个线程和两个线程来进行测试线程执行的时间

    串行
    public static void serial(){
        long beg = System.currentTimeMillis();
        int a = 0;
        for (int i = 0; i  

2.并发

        long beg = System.currentTimeMillis();
        Thread thread1 = new Thread(() ->{
            int a = 0;
            for (int i = 0; i {
            int b = 0;
            for (int i = 0; i  

从以上结果不能看出,并发执行的效率要高于串行执行的效率,但是并不是高于串行的一倍,效率提升接近了50%
但是并不是说并发编程就一定比串行编程的效率一定就高,具体情况具体分析
例如count的值变为1_0000;如果是这样的话,你会发现,串行的速度要高于并发执行的速度,这是因为系统创建线程也需要时间,如果自增变量花费了100ms,但创建一个线程就花费了200ms,显然,并发执行所需要的时间就会相对提高
所以多线程编程适用于CPU高度密集,程序需要大量的计算,使用多线程就可以更充分地利用CPU的多核资源

 start()方法与run()方法

⬆️上文我们提到了start()方法,start()是真的决定了系统中是否能真正的创建出进程,run方法和start方法所表现出的运行结果一致,但是两个方法的含义却截然不同.
经典面试题****start与run方法的区别

run():只是一个普通的方法,描述了任务的内容
start():却是一个特殊的方法,内部会在系统中中创建出一个线程

线程的中断

线程停下来的关键是让线程对应的run()方法执行完
对于main这个特殊的线程,得是main方法执行完,线程就完了

    可以手动的创建一个标识位(自己创建的变量 boolean类型),来控制线程是否要执行结束
public class TestDemo7 {
    private static boolean isQuite = false;
    public static void main(String[] args) {
        Thread thread1 = new Thread(() ->{
            while(!isQuite){
                System.out.println("hello thread1");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },"thread t1");
        thread1.start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        isQuite = true;
        System.out.println("终止t线程!");
    }

根据上述代码,不难看出在main线程中控制这个标志位,就能够终止线程,此处是因为多个线程共用一个虚拟地址空间,所以main中的isQuite和t线程的isQuite是一个值,显然这种自定义标志位的方法是不够严谨的,所以有以下方法

    使用Thread中内置的一个标志位来进行判定
    Thread.interrupted() 这是一个静态的方法一般不用Thread.currentThread().isInterrupted 这是一个实例方法.其中currentThread能够获取当前的实例(无脑用)
public class TestDemo8 {
    public static void main(String[] args) {
        Thread thread = new Thread(()->{
            while(!Thread.currentThread().isInterrupted()){
                System.out.println("hello");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    break;
                }
            }
        });
        thread.start();
        try {
            thread.sleep(6000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        thread.interrupt();
    }
}

thread.interrupt()调用这种方法可能会产生两种情况

    如果线程是就绪状态,就是设置标志位是true;如果线程是堵塞状态(sleep休眠了)就会出发一个InterruptedException
线程的等待

在并发编程中,处理器调度的顺序是不确定的,线程在执行的时候,可以看作是(随机,无序)的,显然这种情况是不好的,所以就需要我们人工来控制,线程等待就是其中一种

线程等待;此处的线程等待控制的是线程结束的时间,而非线程开始的时间

join方法
join方法就是我们线程等待的一种方法,哪个线程调用的join方法,哪个线程就会遭遇堵塞

Thread thread1 = new Thread(() ->{
            int a = 0;
            for (int i = 0; i {
            int b = 0;
            for (int i = 0; i  

如上代码

thread1.join();此代码的含义是:调用这个方法的线程是主函数,针对thread1这个线程调用的,也就是说需要main线程等thread1执行完之后,才能执行

通过线程等待,就是控制t线程执行完之后,main线程才能执行.一定程度上干预了这两个线程的执行顺序.

join()的意思是死等,显然这是不合理的所以我们需要在括号中加入参数
join(1000)含义是:如果在一秒内线程结束了,此时join返回
如果一秒内线程还没有结束,join也返回(劳资不等了),在日常中这样的等待都不会是死等,都会有时间限制的

 线程获取引用

这个知识点我们在此不做过多解释你只需要知道Thread.currentThread().getName()这个方法就足够,哪个线程使用这个方法,就能够获取到哪个线程的实例

线程的休眠

所谓的线程休眠就是在线程中使用**sleep()**方法
调用这个方法后线程就会变为堵塞状态
进程中有多个线程,线程一般被双向链表穿起来成为就绪队列,一旦使用这个方法线程就会从就绪队列成为堵塞队列(一般sleep也会和join方法一样有时间限制)等到时间限制过了之后,线程就会从堵塞队列重新回到就绪队列

此处需要注意,在线程调用时,不会从堵塞队列里调用线程,只有就绪队列才有可能被调用


大家可以对照上图参考

以上就是Thread类使用的基础知识,在未来的博客中,我们还会对线程相关的知识点做详细的介绍

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/777949.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号