当前位置: 首页 > news >正文

一篇文章带你理解Thread(多线程)的基础用法

目录

1.线程创建

1.1通过继承类创建

1.2通过类实现接口创建

1.3通过内部类继承Thread来创建

1.4通过内部类实现Runnable接口来创建

1.5通过lambda表达式创建

2.线程中断

2.1自定义标志位

2.2interrupt()方法

3.线程等待

4.线程休眠

5.获取线程实例


1.线程创建

        线程创建有五种方法,这里喜欢用那种用那种

注意:下文中的start方法才是多线程开始执行,run方法只是表明需要执行的内容

1.1通过继承类创建


class A extends Thread {
    @Override
    public void run() {
        System.out.println("通过继承Thread类创建线程");
    }
}



public class Main {
    public static void main(String[] args) {
        A a = new A();
        //这里的start是线程开始执行的方法,执行的是Thread中的run方法
        a.start();
    }
}

这里需要注意,当我们继承Thread类的时候,必须重新run方法,相当于是在给线程分配任务

1.2通过类实现接口创建

class B implements Runnable{
    @Override
    public void run() {
        System.out.println("通过实现Runnable接口来创建");
    }
}


public class Main {
    public static void main(String[] args) {

        //这里通过Thread类型对象,对构造方法传入一个实现了Runnable接口的类来创建
        Thread b = new Thread(new B());
        b.start();
    }
}

1.3通过内部类继承Thread来创建


public class Main {
    public static void main(String[] args) {
     

        Thread c = new Thread(){
            @Override
            public void run() {
                System.out.println("通过匿名内部类继承Thread来创建");
            }
        };
        c.start();
    }
}

1.4通过内部类实现Runnable接口来创建

public class Main {
    public static void main(String[] args) {
    
        Thread d = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("通过匿名内部类实现Runnable接口来实现");
            }
        });
        d.start();

        
    }
}

1.5通过lambda表达式创建

public class Main {
    public static void main(String[] args) {
 

        Thread e = new Thread(()-> System.out.println("使用lambda表达式创建"));
        e.start();



    }
}

最后我们看一下所有的执行结果

总结:

可以发现,只有通过继承Thread类的时候,不需要创建Thread对象,其余的都需要创建Thread对象

2.线程中断

2.1自定义标志位

这种方法很简单,就是自己定义一个变量,用来标识线程结束,当执行某条语句,则线程结束,就不进行演示了

2.2interrupt()方法

不仅可以用自定义的标志位,我们还可以调用interrupt方法,来进行线程中断


public class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            //通过Thread.interrupted()判断是否存在标志位,若不存在则一直执行while,若存在则停止并且清除标志位
           while(!Thread.interrupted()){
               System.out.println("123");
           }
        });
        t1.start();
        Thread.sleep(1);
//通过t1.interrupt()创建标志位
        t1.interrupt();
    }
}

上述代码中的含义是,开始没标志位,所以while语句可以一直执行,当我们执行到t1.interrupt之后,创建了一个标志位,这样我们就拥有了标志位,所以while循环就会终止,代码的运行结果如下

可以看到我们的线程是有停止的

 我们总结一些常用的标志位用法

1.Thread.interrupt()       设置标志位,若线程阻塞则抛出异常,并且清除标志位

2.Thread.interrupted()     判断是否有标志位,若存在返回true,否则返回false,最后清除标志位 

3.Thread..currentThread().isInterrputed()      判断是否有标志位,若存在返回true,否则返回false,最后不清除标志位 

第三个个currentThread是得到当前线程的引用,通过这个引用再去调用isInterrputed方法

 

可以看到,isInterrupted方法是线程实例中的方法,不是类方法,所以我们需要通过引用来调用

3.线程等待

在多线程中,一个线程等待另一个线程,通常使用jion()方法

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                System.out.println("别急,我还没结束呢");
            }
            System.out.println("我结束了");
        });
        t1.start();
        t1.join();
        System.out.println("你终于结束了");
    }
}

看这段代码,就是让主线程去等待t1线程,就是通过调用t1的join()方法来实现的,看一下运行结果

可以看到,当我们的主线程走到t1.join()之后,进行了阻塞等待,然后等t1执行结束了,才开始执行主线程后面的内容,这就是线程的等待

4.线程休眠

线程休眠我们通常使用sleep方法,这个方法是存在于Thread中的类方法,需要传入一个参数,单位是毫秒,就是让当前线程阻塞等待多长时间之后,再执行,看具体实现

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 1000; i++) {
                System.out.println("别急,我还没结束呢");
            }
            System.out.println("我结束了");
        });
        t1.start();

        Thread.sleep(1);
        System.out.println("============================================================");
    }
}

看这样一段代码,我们让主线程一秒后打印一串'=',当我们运行线程的时候

可以看到,主线程等待一秒后,打印了=,但是t1并未执行结束,但是我们的主线程调用的是sleep方法,所以并不会无限制的等下去

注意:这里的sleep需要处理编译异常,

InterruptedException

 

我们可以像上面一样加上声明,也可以使用try{}catch来处理,这个我们在异常的时候已经说过了,就不再赘述了

 

5.获取线程实例

这里我们使用currentThread来获取线程的实例,这里和this有异曲同工之妙,在哪里调用的,就会获取到哪个实例,看代码实现

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            System.out.println(Thread.currentThread());
        });
        t1.start();
        System.out.println(Thread.currentThread());
       
    }
}

运行结果是这样的

我们可以看到,在main中的是main线程,t1是Thread-0线程,我们做个测试,如果,在主线程中通过t1来调用currentThread获取到的是哪个线程呢?

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            
        });
        t1.start();
        
       
        System.out.println(t1.currentThread());
    }
}

 我们可以看到,我们在主线程中通过t1去调用currentThread()方法,得到结果也是和我们预期的一样

为什么?

因为我们的currentThread()是一个静态方法,所以不论你通过什么Thread的实例调用,其实结果都是一样的,只有一个,就是当前线程的引用 

以上就是多线程的一些基本使用了

        感谢阅读

相关文章:

  • harbor部署实录
  • 计算机毕业设计ssmEE的仓库管理系统93c6b系统+程序+源码+lw+远程部署
  • MySQL group by后取每个分组中最新一条数据
  • JVM:(十六)垃圾回收器
  • 节点流和处理流详解
  • MySQL binlog 数据恢复
  • ArcGIS中添加在线地图(影像图、街道图等)
  • Opencv图像模板匹配
  • c语言进阶: 指针的进阶(上)
  • python使用PIL模块加载图像、通过resize函数改变图像的大小、使用save函数保存处理过的图像
  • Python点云显示:open3d快速上手
  • vue转electron项目以及使用fs报错:Module not found: Error: Can‘t resolve ‘fs‘ in解决办法
  • 【MATLAB教程案例14】基于ACO蚁群优化算法的函数极值计算matlab仿真及其他应用
  • 优化算法 - Adam算法
  • Open3D (C++) 点云变换
  • [case10]使用RSQL实现端到端的动态查询
  • 0x05 Python数据分析,Anaconda八斩刀
  • export和import的用法总结
  • Facebook AccountKit 接入的坑点
  • flutter的key在widget list的作用以及必要性
  • GraphQL学习过程应该是这样的
  • Hibernate【inverse和cascade属性】知识要点
  • Intervention/image 图片处理扩展包的安装和使用
  • Java超时控制的实现
  • js面向对象
  • LeetCode29.两数相除 JavaScript
  • mongodb--安装和初步使用教程
  • Quartz实现数据同步 | 从0开始构建SpringCloud微服务(3)
  • seaborn 安装成功 + ImportError: DLL load failed: 找不到指定的模块 问题解决
  • 阿里云ubuntu14.04 Nginx反向代理Nodejs
  • 猴子数据域名防封接口降低小说被封的风险
  • 快速体验 Sentinel 集群限流功能,只需简单几步
  • 前端每日实战:70# 视频演示如何用纯 CSS 创作一只徘徊的果冻怪兽
  • 手写一个CommonJS打包工具(一)
  • AI又要和人类“对打”,Deepmind宣布《星战Ⅱ》即将开始 ...
  • Nginx实现动静分离
  • Spark2.4.0源码分析之WorldCount 默认shuffling并行度为200(九) ...
  • 组复制官方翻译九、Group Replication Technical Details
  • ​LeetCode解法汇总2670. 找出不同元素数目差数组
  • ​queue --- 一个同步的队列类​
  • $emit传递多个参数_PPC和MIPS指令集下二进制代码中函数参数个数的识别方法
  • (3)Dubbo启动时qos-server can not bind localhost22222错误解决
  • (AngularJS)Angular 控制器之间通信初探
  • (Matalb分类预测)GA-BP遗传算法优化BP神经网络的多维分类预测
  • (博弈 sg入门)kiki's game -- hdu -- 2147
  • (附源码)spring boot球鞋文化交流论坛 毕业设计 141436
  • (转) RFS+AutoItLibrary测试web对话框
  • (转)如何上传第三方jar包至Maven私服让maven项目可以使用第三方jar包
  • .bat批处理(二):%0 %1——给批处理脚本传递参数
  • .htaccess 强制https 单独排除某个目录
  • .NET MVC、 WebAPI、 WebService【ws】、NVVM、WCF、Remoting
  • .NET牛人应该知道些什么(2):中级.NET开发人员
  • ??javascript里的变量问题
  • @Autowired多个相同类型bean装配问题
  • [14]内置对象