展开菜单
首页 精品内容 本月促销 装机必备 Windows PDF教程 macOS软件 IOS软件 Android AI 专题
全部分类

当前位置:

首页 > 编程开发 > Java多线程Thread类如何使用

Java多线程Thread类如何使用

Thread类的基本用法1.创建子类,继承自Thread并且重写run方法:classMyThreadextendsThread{@Overridepublicvoidrun(){System.out.println("hellothread");}}publicclassDemo1{publicstaticvoidmain(String[]args){//最基本的创建线程的办法.Threadt=newMyThread();//调用了start方法才是真正的在系统中创建了线程,执行run方法t.start

    Thread类的基本用法

    1.创建子类,继承自Thread并且重写run方法:

    class MyThread extends Thread {
        @Override
        public void run() {
            System.out.println("hello thread");
        }
    }
    public class Demo1 {
        public static void main(String[] args) {
            // 最基本的创建线程的办法.
            Thread t = new MyThread();
            //调用了start方法才是真正的在系统中创建了线程,执行run方法
            t.start();
        }
    }

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

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

    3.匿名内部类

    创建了一个匿名内部类,继承自Thread类,同时重写run方法,再new出匿名内部类的实例

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

    new的Runnable,针对这个创建的匿名内部类,同时new出的Runnable实例传给Thread的构造方法

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

    4.lambda表达式 lambda代替Runnable

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

    线程指标

    1.isDaemon();
    是否后台线程 后台线程不影响进程退出,不是后台线程会影响进程退出

    2.isAlive();
    是否存活 在调用start前系统中是没有对应线程的,run方法执行完后线程就销毁了,t对象可能还存在

    3.isinterrupted();
    是否被中断

    run和start的区别

    run单纯的只是一个普通方法描述了任务的内容 start则是一个特殊的方法,内部会在系统中创建线程

    中断线程

    线程停下来的关键是要让对应run方法执行完,对于main线程来说main方法执行完了才会终止

    1.手动设置标志位
    在线程中控制这个标志位就能影响到这个线程结束,但是此处多个线程共用一片虚拟空间,因此main线程修改的isQuit和t线程判断的isQuit是同一个值

    public class Demo10 {
        // 通过这个变量来控制线程是否结束.
        private static boolean isQuit = false;
        public static void main(String[] args) {
            Thread t = new Thread(() -> {
                while (!isQuit) {
                    System.out.println("hello thread");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
            t.start();
    
            // 就可以在 main 线程中通过修改 isQuit 的值, 来影响到线程是否退出
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            // main 线程在 5s 之后, 修改 isQuit 的状态.
            isQuit = true;
        }
    }

    2.使用Thread中内置的一个标志位来判定 Thread.interruted()这是一个静态方法 Thread.currentThread().isInterrupted()这是一个实例方法,其中currentThread能够获取到当前线程的实例

    public class Demo7 {
        public static void main(String[] args)  {
            Thread t = new Thread(() -> {
                while(!Thread.currentThread().isInterrupted()){
                    System.out.println("hello");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                        // 当触发异常之后, 立即就退出循环~
                        System.out.println("这是收尾工作");
                        break;
                    }
                }
            });
            t.start();
            try{
                Thread.sleep(5000);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
            // 在主线程中, 调用 interrupt 方法, 来中断这个线程.
            // t.interrupt 的意思就是让 t 线程被中断!!
            t.interrupt();
        }
    }

    需要注意的是调用这个方法t.interrupt()可能会产生两种情况:
    1)如果t线程处在就绪就设置线程的标志位为true
    2)如果t线程处在阻塞状态(sleep),就会触发一个InterruptExeception

    线程等待

    多个线程之间调度顺序是不确定的,有时候我们需要控制线程之间的顺序,线程等待就是一种控制线程执行顺序的手段,此处的线程等待只要是控制线程结束的先后顺序。
    哪个线程中的join,哪个线程就会阻塞等待直到对应的线程执行完毕为止。

    t.join();
    调用这个方法的线程是main线程,针对t这个对象调用的此时就是让main等待t。
    代码执行到join这一行就停下了,让t先结束然后main继续。

    t.join(10000);
    join提供了另一个版本为带一个参数的,参数为等待时间10s之后join直接返回不再等待

    Thread.currentThread()

    能够获取当前线程的应用,哪个线程调用的currentThread就获取到哪个线程的实例 对比this如下:
    对于这个代码来说,通过继承Thread的方法来创建线程。此时run方法中直接通过this拿到的就是当前Thread的实例

    public class Demo4 {
        public static void main(String[] args) {
            Thread t = new Thread(){
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                    System.out.println(this.getName());
                }
            };
            t.start();
        }
    }

    然而此处this不是指向Thread类型,而是指向Runnable,Runnable只是一个单纯的任务没有name属性,要想拿到线程名字只能通过Thread.currentThread()

    public class Demo5 {
        public static void main(String[] args) {
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    //err
                    //System.out.println(this.getName());
                    //right
                    System.out.println(Thread.currentThread().getName());
                }
            });
            t.start();
        }
    }

    进程状态

    针对系统层面:

    • 就绪

    • 阻塞

    java中Thread类进一步细化:

    • NEW:把Thread对象创建好了但是还没有调用start

    • TERMINATED:操作系统中的线程已执行完毕销毁,但是Thread对象还在获取到的状态

    • RUNNABLE:就绪状态,处在该状态的线程就是在就绪队列中,随时可以调度到CPU上

    • TIME_WAITING:调用了sleep就会进入到该状态,join(超时时间) BLOCKED:当前线程在等待锁导致了阻塞

    • WAITING:当前线程在等待唤醒

    状态转换图:

    Java多线程Thread类如何使用

    线程安全问题

    定义:操作系统中线程调度是随机的,导致程序的执行可能会出现一些bug。如果因为调度随机性引入了bug线程就是不安全的,反之则是安全的。
    解决方法:加锁,给方法直接加上synchronized关键字,此时进入方法就会自动加锁,离开方法就会自动解锁。当一个线程加锁成功的时候,其他线程尝试加锁就会触发阻塞等待,阻塞会一直持续到占用锁的线程把锁释放为止。

    synchronized public void increase() {
            count++;
    }

    线程不安全产生的原因:

    • 1.线程是抢占式执行,线程间的调度充满随机性。

    • 2.多个线程对同一个变量进行修改操作

    • 3.针对变量的操作不是原子的

    • 4.内存可见性也会影响线程安全(针对同一个变量t1线程循环进行多次读操作,t2线程少次修改操作,t1就不会从内存读数据了而是从寄存器里读)

    • 5.指令重排序,也是编译器优化的一种操作,保证逻辑不变的情况下调整顺序,解决方法synchronized。

    内存可见性解决方法:

    • 1.使用synchronized关键字 使用synchronized不光能保证指令的原子性,同时也能保证内存的可见性。被synchronized包裹起来的代码编译器就不会从寄存器里读。

    • 2.使用volatile关键字 能够保证内存可见性,禁止编译器作出上述优化,编译器每次执行判定相等都会重新从内存读取。

    synchronized用法

    在java中每个类都是继承自Object,每个new出来的实例里面一方面包含自己安排的属性,另一方面包含了“对象头”即对象的一些元数据。加锁操作就是在这个对象头里面设置一个标志位。

    1.直接修饰普通的方法

    使用synchronized的时候本质上是对某个“对象”进行加锁,此时的锁对象就是this。加锁操作就是在设置this的对象头的标志位,当两个线程同时尝试对同一个对象加锁的时候才有竞争,如果是两个线程在针对两个不同对象加锁就没有竞争。

    class Counter{
    	public int count;
    	synchronized public void increase(){
    	count++;
    	}
    }

    2.修饰一个代码块

    需要显示制定针对那个对象加锁(java中的任意对象都可以作为锁对象)

    public void increase(){
        synchronized(this){
        count++;
        }
    }

    3.修饰一个静态方法

    相当于针对当前类的类对象加锁,类对象就是运行程序的时候。class文件被加载到JVM内存中的模样。

    synchronized public static void func(){
    }

    或者

    public static void func(){
        synchronized(Counter.class){
    
        }
    }

    监视器锁monitor lock

    可重入锁就是同一个线程针对同一个锁,连续加锁两次,如果出现死锁就是不可重入锁,如果不会死锁就是可重入的。因此就把synchronized实现为可重入锁,下面的例子里啊连续加锁操作不会导致死锁。可重入锁内部会记录所被哪个线程占用也会记录加锁次数,因此后续再加锁就不是真的加锁而是单纯地把技术给自增。

    synchronized public void increase(){
        synchronized(this){
            count++;
        }
    }

    死锁的其他场景

    • 1.一个线程一把锁

    • 2.两个线程两把锁

    • 3.N个线程M把锁(哲学家就餐问题,解决方法:先拿编号小的筷子)

    死锁的四个必要条件(前三个都是锁本身的特点)

    • 1.互斥使用,一个锁被另一个线程占用后其他线程就用不了(锁的本质,保证原子性)

    • 2.不可抢占,一个锁被一个线程占用后其他线程不可把这个锁给挖走

    • 3.请求和保持,当一个线程占据了多把锁之后,除非显示的释放否则这些锁中都是该线程持有的

    • 4.环路等待,等待关系成环(解决:遵循固定的顺序加锁就不会出现环路等待)

    java线程类:

    • 不安全的:ArrayList,LinkedList,HashMap,TreeMap,HashSet,TreeSet,StringBuilder

    • 安全的:Vector,HashTable,ConcurrentHashMap,StringBuffer,String

    volatile

    禁止编译器优化保证内存可见性,产生原因:计算机想执行一些计算就需要把内存的数据读到CPU寄存器中,然后再从寄存器中计算写回到内存中,因为CPU访问寄存器的速度比访问内存快很多,当CPU连续多次访问内存结果都一样,CPU就会选择访问寄存器。

    JMM(Java Memory Model)Java内存模型

    就是把硬件结构在java中用专业的术语又重新抽象封装了一遍。

    工作内存(work memory)其实指的不是内存,而是CPU寄存器。
    主内存(main memeory)这才是主内存。
    原因:java作为一个跨平台编程语言要把硬件细节封装起来,假设某个计算机没有CPU或者内存同样可以套到上述模型中。

    寄存器,缓存和内存之间的关系

    CPU从内存取数据太慢,因此把数据直接放到寄存器里来读,但寄存器空间太紧张于是又搞了一个存储空间,比寄存器大比内存小速度比寄存器慢比内存快称为缓存。寄存器和缓存统称为工作内存。

    寄存器,缓存和内存之间的关系图

    Java多线程Thread类如何使用

    • 存储空间:CPU

    • 速度:CPU>L1>L2>L3>内存

    • 成本:CPU>L1>L2>L3>内存

    volatile和synchronized的区别

    • volatile只是保证可见性不保证原子性,只是处理一个线程读和一个线程写的过程。

    • synchronized都能处理

    wait和notify

    等待和通知处理线程调度随机性问题的,join也是一种控制顺序的方式更倾向于控制线程结束。wait和notify都是Object对象的方法,调用wait方法的线程就会陷入阻塞,阻塞到有线程通过notify来通知。

    public class Demo9 {
        public static void main(String[] args) throws InterruptedException {
            Object object = new Object();
            System.out.println("wait前");
            object.wait();
            System.out.println("wait后");
        }
    }

    wait内部会做三件事;

    • 1.先释放锁

    • 2.等待其他线程的通知

    • 3.收到通知后重新获得锁并继续往下执行

    因此想用wait/notify就得搭配synchronized

    public class Demo9 {
        public static void main(String[] args) throws InterruptedException {
            Object object = new Object();
            synchronized (object){
                System.out.println("wait前");
                object.wait();
                System.out.println("wait后");
            }
        }
    }

    注意:wait notify都是针对同一对象来操作的,例如现在有一个对象o,有10个线程都调用了o.wait,此时10个线程都是阻塞状态。如果调用了o.notify就会把10个线程中的一个线程唤醒。而notifyAll就会把所有10个线程全都给唤醒,此时就会竞争锁。

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Java thread
    相关文章 更多
    精品专题 更多
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    macOS软件

    正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

    IOS软件

    正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

    AI

    正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

    Mac软件 更多
    WPS Office macOS版
    WPS Office macOS版

    WPS Office是一款面向macOS用户的综合办公套件,将文字处理、电子表格、演示文稿、PDF工具、模板与云协作整合在同一应用中。它兼容常见Microsoft Office格式,支持Intel及Apple芯片Mac,基础功能可免费使用,

    Shapr3D macOS版
    Shapr3D macOS版

    Shapr3D是一款面向工业设计、机械工程、建筑概念和三维打印工作流的CAD软件。Mac版采用Parasolid建模内核,支持草图约束、实体建模、工程图、可视化渲染及常见CAD格式交换,并可通过账户在多台设备之间同步项目。

    REAPER macOS版
    REAPER macOS版

    REAPER是Cockos开发的数字音频工作站,提供多轨音频与MIDI录制、剪辑、处理、混音和母带制作工具。Mac版兼容Intel与Apple芯片,支持AU、VST、VST3、CLAP等插件格式,并提供高度可定制的工作流程。

    Ableton Live macOS版
    Ableton Live macOS版

    Ableton Live 是面向音乐制作人与现场表演者的数字音频工作站,提供编曲视图、独具特色的现场视图、音频录制、MIDI创作、实时变速、乐器及效果器。Mac版原生支持Apple芯片,并可连接音频接口、MIDI控制器和第三方插件。

    Adobe After Effects macOS版
    Adobe After Effects macOS版

    Adobe After Effects 是面向动态图形、影视特效与视频合成的专业创作软件。它提供关键帧动画、遮罩抠像、运动跟踪、三维空间、文字动画和表达式等工具,并可与 Premiere Pro、Photoshop、Illustrator

    Adobe Audition macOS版
    Adobe Audition macOS版

    Adobe Audition 是面向播客、影视后期、音乐制作及内容创作者的专业音频工作站,提供波形精修、多轨录制与混音、频谱编辑、降噪修复、响度匹配和效果处理工具,并可与 Adobe Premiere 协同完成视频声音制作。

    Adobe Bridge macOS版
    Adobe Bridge macOS版

    Adobe Bridge 是面向摄影师、设计师及内容团队的免费数字资产管理工具,可集中预览照片、视频和 Adobe 项目文件,并利用评级、标签、关键词、元数据、筛选与收藏集完成分类检索。它还支持批量重命名、格式导出、相机导入及 Camera

    Adobe Illustrator macOS版
    Adobe Illustrator macOS版

    Adobe Illustrator 是 Adobe 推出的专业矢量图形设计软件,适合在 Mac 上制作标志、图标、插画、包装、信息图及印刷版面。它以路径和锚点构建可无损缩放的图形,并提供钢笔、形状、文字、图像描摹、渐变、画板及生成式功能。

    Adobe InDesign macOS版
    Adobe InDesign macOS版

    Adobe InDesign 是面向印刷品与数字出版物的专业版面设计软件,可在 Mac 上制作书籍、杂志、宣传册、海报、报告及交互式文档。它提供精细的文字样式、网格、母版、长文档管理和印前输出能力。

    Adobe Lightroom Classic macOS版
    Adobe Lightroom Classic macOS版

    Adobe Lightroom Classic 是面向桌面摄影工作流的照片管理与后期处理软件,可将原始照片保存在本地硬盘,通过目录、关键词、评分和收藏夹高效整理图库,并提供 RAW 冲印、蒙版、镜头校正、批量同步及多格式导出等功能。

    Adobe Media Encoder macOS版
    Adobe Media Encoder macOS版

    Adobe Media Encoder 是 Adobe 推出的专业音视频编码与转码工具,可通过队列、预设和监视文件夹批量完成格式转换、代理文件创建及多平台成片输出,并与 Premiere Pro、After Effects 等软件紧密协作。

    Adobe Photoshop macOS版
    Adobe Photoshop macOS版

    Adobe Photoshop 是面向摄影师、设计师和内容创作者的专业图像处理软件,提供图层、蒙版、选区、修复、调色、文字排版、智能对象及生成式编辑等能力。Mac 版支持 Intel 与 Apple Silicon 处理器。

    WINDOWS 更多
    Adobe Photoshop Windows版
    Adobe Photoshop Windows版

    Adobe Photoshop 是面向摄影师、设计师和内容创作者的专业图像处理工具,可在 Windows 上完成照片修饰、选区抠图、图层合成、文字排版、绘画及生成式编辑。软件采用订阅授权,由 Creative Cloud 管理安装、更新与许

    Adobe InDesign Windows版
    Adobe InDesign Windows版

    Adobe InDesign 是面向印刷与数字出版的专业页面排版工具,可制作书籍、杂志、宣传册、海报、交互式 PDF 和电子书。它提供精细的文字样式、多页面管理、印前检查及多格式输出能力,并能与 Photoshop、Illustrator

    Adobe Illustrator Windows版
    Adobe Illustrator Windows版

    Adobe Illustrator 是用于绘制矢量图形、插画、图标、徽标和版式的专业设计工具。它以路径和锚点为核心,作品放大后仍能保持清晰,并提供画板、文字、渐变、图像描摹及精确变换等功能,适合品牌视觉、印刷物料、数字界面和商业插画创作。

    Adobe Bridge Windows版
    Adobe Bridge Windows版

    Adobe Bridge 是 Adobe 推出的创意资产管理工具,可集中预览、分类和查找照片、视频、PDF及多种设计文件,并支持元数据、关键词、评级、批量重命名和格式导出。它可与 Photoshop、Illustrator 等应用衔接,

    Affinity Photo Windows版
    Affinity Photo Windows版

    Affinity Photo 是一款面向摄影师、修图师和视觉设计人员的桌面图像编辑工具,提供 RAW 显影、多图层合成、蒙版、实时滤镜、批处理和色彩管理等功能。原独立产品已停止销售,其照片编辑能力已延续至免费的新 Affinity 应用;

    Adobe Lightroom Classic Windows版
    Adobe Lightroom Classic Windows版

    Adobe Lightroom Classic 是面向 Windows 桌面摄影工作流的照片管理与无损编辑工具,可通过目录集中整理大型图库,并完成 RAW 显影、局部蒙版、批量调整、打印和多格式导出。它强调本地文件管理与精细控制,

    Figma Windows版
    Figma Windows版

    Figma 是面向产品设计与开发团队的云端协作平台,可在 Windows 桌面客户端中完成界面绘制、组件管理、交互原型、评论评审和开发交付。文件保存在云端,多名成员能够同步编辑并共享设计系统;官方同时提供免费 Starter 方案及按席位计

    Affinity Designer Windows版
    Affinity Designer Windows版

    Affinity Designer 是面向矢量图形、数字插画和界面设计的专业创作工具,可在矢量、像素与导出工作区之间快速切换。它提供曲线编辑、形状构建、画板、排版、图层和专业色彩管理,并支持常见设计文件的导入及多种印刷、网页格式输出。

    Capture One Pro Windows版
    Capture One Pro Windows版

    Capture One Pro 是面向摄影师和影像团队的专业桌面照片处理工具,提供相机定制色彩配置、RAW转换、图层与蒙版、联机拍摄、目录及会话管理等功能。它适合棚拍、人像、商业产品、婚礼和风光摄影,

    Adobe Acrobat Pro Windows版
    Adobe Acrobat Pro Windows版

    Adobe Acrobat Pro 是面向专业 PDF 工作的综合解决方案,可在 Windows 中创建、编辑、转换、比较、整理和保护文档,并支持表单、电子签名、扫描件文字识别及敏感信息永久遮盖。订阅还包含网页、移动服务和云端协作能力,

    Adobe After Effects Windows版
    Adobe After Effects Windows版

    Adobe After Effects 是面向动态图形、动画与影视视觉特效制作的专业工具,可完成关键帧动画、图层合成、遮罩跟踪、抠像、文字动画和二维三维元素整合。Windows 版通过 Adobe Creative Cloud 安装及更新,

    DaVinci Resolve Windows版
    DaVinci Resolve Windows版

    DaVinci Resolve是Blackmagic Design推出的一体化影视后期工具,将素材管理、非线性剪辑、专业调色、Fusion视觉特效、Fairlight音频处理和成片交付整合在统一工程中。免费版已覆盖多数个人创作需求,