【Java面试】并发编程实战(线程控制操作详解)

Java并发实战 并发编程的问题:可见性,原子性,有序性 问题由来: 缓存导致的可见性: 缓存最开始是为了解决CPU单核时代时,CPU和内存交互问题,每个CPU都有自己的缓存,但是在多核时代时,CPU自己的缓存之间是具有独立性的,所以数据从缓存到内存之间是隔离的,这也就导致了内存可见性的原因。 单核时代: 多核时代: 线程切换带来的原子性问题: 在单核时代,应用要是想进行并行运行,是需要CPU对运行任务每隔一定的“时间片”就进行切片处理的,这就导致了多个线程对同一个资源就行修改的时候发生无原子性的问题。 编译优化带来的有 阅读详情

前言

在使用Java实际编程中,多线程可以说是无所不在,凡是需要并发执行的都可以用到它,一个应用程序中不用多线程将会是很糟糕的事情,所以掌握线程以及它的控制操作是非常重要的。

通过本篇文章来今天带大家一文掌握线程控制操作,感谢您的观看。

目录

📌前言

📱一、线程的基本概念

✏️1.并行和并发

✏️2.进程和线程

💻二、线程的运行状态

🔦三、线程编程实践

📝1.线程两种定义方法

📝2.启动线程

📝3.同时定义和启动线程

📝 4.线程弹出与暂停

📝5.线程等待与唤醒

📝6.线程中断

一、线程的基本概念

1.并行和并发

并行:多个CPU核心同时工作,处理不同的任务。
并发:多个任务交替使用 CPU 核心工作,以提高 CPU 利用率。

2.进程和线程

**进程:**程序的一次执行。由操作系统创建并分配资源,执行一个单独的任务。
进程是系统进行资源分配和调度的独立单位,每个进程都有自己的内存空间和系统资源。进程内所有线程共享堆存储空间,保存程序中定义的对象和常量池。

Windows系统中,每个运行的 Java 程序都是一个独立的进程。

**线程:**进程内的执行单元,不分配单独的资源,执行一个单独的子任务。
线程是进程内调度和分派的基本单位,共享进程资源。每个线程有自己的独立的栈存储空间,保存线程执行的方法以及基本类型的数据。

运行的 Java 程序内含至少一个主线程 main ,用户可以在 Java 程序中自定义并调用多个线程。 JVM 垃圾回收线程也是一个独立的线程。

​

二、线程的运行状态

线程除创建状态 New 和结束状态 Terminate 外,主要有以下几种运行状态:
**①运行(Running) :**CPU 正在执行线程。
**②就绪(Runnable) :**线程一切就绪,等待 CPU 执行。

运行/就绪状态 统称为可运行状态 Runnable。 Java 程序中,线程在 运行/就绪状态 之间的切换由 JVM 自动调度,开发者无法获知。线程之间的调度采用分优先级多队列时间片轮转算法。进程在执行完 CPU 时间片切换到就绪状态之前会先保存自己的状态,下次进入运行状态时再重新加载。

**③阻塞(Blocked) :**线程因缺少其他资源,比如请求资源被上锁而暂停执行。在获得资源后进入就绪状态。
**④等待(Waitting) :**线程接受了等待指令,释放资源暂停执行。在超时/接受唤醒指令后进入就绪状态。

​

三、线程操作实践

Runnable 接口内唯一声明了 run 方法,由 Thread 类实现。开发者在 run 方法中定义运行时线程将要执行的功能,线程开启后由Java虚拟机自动调用并执行。如果开发者主动调用 run 方法,则只会当作普通方法执行。

1.线程两种定义方法

①继承 Thread 类,重写 run 方法。

public class MyThread extends Thread {
   @Override
   public void run() {
       System.out.println(Thread.currentThread().getName());
   }
}

②实现 Runnable 接口,实现 run 方法。推荐使用,避免了单继承的局限性。

public class MyThread implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

2.启动线程

Thread 类定义了 start 方法。调用 start 方法后,系统会开启一个新线程进入就绪状态:由 JVM 会自动对线程进行调度,在运行时调用并执行线程的 run 方法。一个线程只能启动一次。

①如果自定义线程类继承 Thread 类,直接启动。

public class Main {
   public static void main(String[] args) {
       MyThread t1 = new MyThread();
       MyThread t2 = new MyThread("ThreadName");
       t1.start();
       t2.start();
   }
}

②如果自定义线程类实现 Runnable 接口,则需要借助 Thread 类启动线程。

public class Main {
   public static void main(String[] args) {
       MyThread mythread = new MyThread();
       Thread t1 = new Thread(mythread);                   // 由系统指定默认线程名 Thread-X
       Thread t2 = new Thread(mythread, "ThreadName");     // 开发者自定义线程名 
       t1.start();
       t2.start();
   }
}

3.同时定义和启动线程

通过匿名内部类方式,我们可以实现同时定义和启动线程的简洁写法。

public class Main {
    public static void main(String[] args) {
        Thread thread = new Thread(new Runnable(){
            public void run(){
                System.out.println(Thread.currentThread().getName());
            }
        }).start();
    }
}

class Test {
   public void method() {
       System.out.println(Thread.currentThread().getName());
   }
}

4.线程弹出与暂停

Thread 类定义了 yield 方法。当前线程执行到 Thread.yield() 方法,会停止运行进入就绪状态。但线程切换到就绪状态后,什么时候被 JVM 调度回运行状态开发者无法控制。

public class ThreadDemo {
    public static void main(String[] args) {
       MyThread mythread = new MyThread();
       Thread t1 = new Thread(mythread);              
       Thread t2 = new Thread(mythread);    
       t1.start();
       t2.start();
    }

    static class MyThread implements Runnable {
        @Override
        public void run() {
            int count = 0;
            for (int i = 0; i < 10000; i++) {
                Thread.yield();                    // 切换到就绪状态
                count++;
                System.out.println(count);
            }         
        }
    }
}

Thread 类定义了 sleep 方法。当前线程执行到 Thread.sleep(1000) 方法,会停止运行进入阻塞状态,但仍会保持对象锁,其他线程不可访问其资源。直到超时后进入就绪状态。调用 sleep 方法需要捕获或抛出 InterruptException 异常。

public class ThreadDemo {
    public static void main(String[] args) {
       MyThread mythread = new MyThread();
       Thread t1 = new Thread(mythread);              
       Thread t2 = new Thread(mythread);    
       t1.start();
       t2.start();
    }

    static class MyThread implements Runnable {
        @Override
        public void run() {
            int count = 0;
            for (int i = 0; i < 10000; i++) {
                try{
                    Thread.sleep(1000);             // 当前线程暂停 1s
                } catch(InterruptException e){
                    e.printStackTrace();
                }

                count++;
                System.out.println(count);
            }         
        }
    }

}

5.线程等待与唤醒

①线程等待

当前线程执行 obj.wait() 方法,线程会停止运行并释放对象锁 obj,其他线程可以访问其资源。同时线程进入 obj 对象的等待池,直到被 notify 方法唤醒进入就绪状态。调用 wait 方法需要捕获或抛出 InterruptException 异常。

wait 方法允许计时等待。当前线程执行 obj.wait(1000) 方法,计时结束后线程会被自动唤醒进入就绪状态。

②线程唤醒

当前线程执行 obj.notify() 方法,会随机从 obj 对象等待池中选择一个线程唤醒,使其进入就绪状态。但是 notify 方法不会释放当前进程的对象锁,如果该线程持有 obj 对象的锁,当前线程释放锁后被唤醒的其他线程才能被执行。如果想被唤醒线程先执行,notify 方法后添加 wait 方法释放锁。

当前线程执行 obj.notifyall() 方法,会将所有 obj 对象等待池中所有线程唤醒。

public class ThreadDemo {
    public static void main(String[] args) {
        MyThread t = new MyThread("t");
        synchronized(t) {                         // 对 t 设置对象锁
            try {
                t.start();
                System.out.println("1");
                t.wait();                         // 当前线程释放 t 锁,进入 t 对象等待池
                System.out.println("4");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    static class MyThread extends Thread {
        @Override
        public void run() {
            synchronized (this) {                 // 对 t 设置对象锁        
                Thread.sleep(1000);
                System.out.println("2");
                this.notify();                    // 随机唤醒一个 t 对象等待池中的线程
                System.out.println("3");
            }
        }
    }
}

6.线程中断

调用 t.stop() 方法可以强制终止线程 t 运行,但强制中断线程可能会造成意想不到的问题,已不推荐使用。

目前主要采用设置线程中断标志的方式,向线程发送中止信号。由线程自行终止运行:

  • 执行 t.interrupt() 方法,将线程 t 中断标志设为 true 。
  • 执行 t.isInterrupted() 方法,查看线程 t 中断标志。
  • 执行 t.interrupted() 方法,查看线程 t 中断标志然后将其设为 false 。
public class ThreadDemo {
    public static void main(String[] args) {
       MyThread mythread = new MyThread();
       Thread t = new Thread(mythread);              
       t.start();
       try {
            Thread.sleep(500);
        } catch (InterruptedException e) {}
       t.interrupt();                            // 设置中断标志为 true
    }

    static class MyThread implements Runnable {
        @Override
        public void run() {
            while (true) {
                System.out.print("hello");
                if(this.isInterrupted()){        // 查看中断标志,若为 true 结束循环
                    break;
                }
            }
        }        
    }

}

【Java面试】并发编程实战(线程控制操作详解)_java并发编程实战 ①继承 Thread 类,重写 run 方法。@Override②实现 Runnable 接口,实现 run 方法。推荐使用,避免了单继承的局限性。@Override通过匿名内部类方式,我们可以实现同时定义和启动线程的简洁写法。}).start(); 阅读详情

相关推荐

面试必问!Java线程控制6大核心方法(start/run区别+实操案例,代码可直接跑)

多线程的核心价值是“并发有序执行”——如果不会控制线程的休眠、插队、优先级,程序只会变成“混乱的并发”:比如主线程提前汇总未统计完的数据、线程无法优雅停止导致资源泄漏。本文6大方法+5个实操案例,帮你精准把控线程执行节奏,彻底摆脱“线程失控”的困境!线程控制是多线程开发的核心,也是面试高频考点,今天6大方法+实操案例覆盖了“启动、休眠、插队、让步、优先级、中断”的全场景。

weixin_42779075的博客 1386

Java并发编程实践

并发编程是指通过设计和实现多线程程序来利用计算机资源和提高程序执行效率的编程方法。它的主要特点是多线程之间的竞争和协作关系。线程安全性是指并发编程中,在多个线程访问共享数据时,对数据的访问不会产生意料之外的后果。实现线程安全性需要从数据的状态变化过程进行分析,并采用相应的线程安全策略。

BXA 2999

多线程 - Java实现并发的几种方法

【Java实现并发的几种方法】

学无止境 3200

Java并发编程实战(一)

xxx系列文章 xxxx系列(1)― xxxx系列(2)― xxxxx系列(3)― 提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录xxx系列文章前言一、一级标题1二、一级标题21.二级标题总结 前言 晚上刷视频刷到河北王校长的bug排除视频,校长深厚的基本功令我汗颜,需要好好学习一下多线程的相关知识了,由此开了这个系列,以极客专栏的学习为主,记下笔记,辅以processon画流程图,尽可能提高自己的并发编程水平 参考链接: 一、一级标题1   Java 里 sync

qq_40662424的博客 1544

Java工程师面试必备试题精讲与实战解析

简介:Java作为企业级应用开发的主流语言,其工程师面试涵盖基础知识、并发编程、内存管理、设计模式、框架应用等多个核心领域。本文整理了Java面试中的关键知识点,包括Java语法基础、异常处理、集合框架、IO流、多线程机制、JVM内存模型、反射与动态代理、Java 8新特性、Spring框架核心原理、数据库操作及网络编程等内容。通过系统梳理和实战导向的讲解,帮助求职者全面掌握面试重点,提升技术竞争力,顺利应对中高级Java岗位的技术考察。

weixin_30591519的博客 366

Java 并发编程实战.pdf

《java并发编程实战》是java并发的圣经。亲自整理目录结构,层级分明(福昕阅读器整理)。高清。

【Java面试】并发编程实战(线程控制操作详解)_java并发编程实战(1)

在使用Java实际编程中,多线程可以说是无所不在,凡是需要并发执行的都可以用到它,一个应用程序中不用多线程将会是很糟糕的事情,所以掌握线程以及它的控制操作是非常重要的。目录📌前言📱一、线程的基本概念✏️1.并行和并发✏️2.进程和线程💻二、线程的运行状态🔦三、线程编程实践📝1.线程两种定义方法📝2.启动线程📝3.同时定义和启动线程📝4.线程弹出与暂停📝5.线程等待与唤醒📝6.线程中断①继承 Thread 类,重写 run 方法。@Override②实现 Runnable 接口,实现 run 方法。

2401_84181193的博客 1050

从STM32转战STC32G?逐飞开源库帮你快速上手GPIO、PWM与ADC(避坑指南)

本文详细介绍了从STM32迁移到STC32G32K128的开发实践,重点解析了GPIO、PWM和ADC等基础外设的设计差异,并提供了基于逐飞开源库的高效应用方案。通过对比两种平台的开发工具和操作方式,帮助开发者快速上手STC32G,避免常见陷阱,提升开发效率。

weixin_30316097的博客 531

【Java面试】并发编程实战(线程控制操作详解)_java并发编程实战(2)

①继承 Thread 类,重写 run 方法。@Override②实现 Runnable 接口,实现 run 方法。推荐使用,避免了单继承的局限性。@Override通过匿名内部类方式,我们可以实现同时定义和启动线程的简洁写法。}).start();

2401_84182271的博客 653

Mplus实战:如何用潜在类别分析(LCA)快速搞定心理学数据分类?

本文详细介绍了如何运用Mplus软件进行潜在类别分析(LCA),以快速处理心理学数据并识别内部异质性群体。文章从数据准备、Mplus语法编写、模型拟合与选择,到结果解读与高级应用(如纳入协变量),提供了完整的实战指南,帮助研究者从变量视角转向个体视角,有效挖掘数据中的潜在子类别。

weixin_28318011的博客 411

解锁微信小程序Camera组件的隐藏技能:连续扫码背后的逻辑与陷阱

本文深入解析微信小程序Camera组件在连续扫码功能中的技术原理与优化方案,涵盖识别率提升、内存管理策略及典型问题排查。通过实战参数对比和代码示例,帮助开发者解决扫码枪应用中的性能损耗与界面卡顿问题,提升零售、物流等场景的工作效率。

weixin_29019241的博客 494

说说java线程调度和线程控制?

说说java线程调度和线程控制?

java1234的博客 1170

一文掌握SourceTree使用(超级详细)

SourceTree是一款开源的代码仓库客户端工具,界面美观,操作简单,具有代码克隆、本地创建、提交代码、撤销修改,拉取(pull)代码、上传(push)代码、合并分支等操作。对于软件开发人员是一款必备的应用软件。

GM_115的博客 3万+

跟面试官整整对线了一个小时的并发编程,最后赢得却是我!

前言 BATJ等互联网公司的高薪和福利吸引了很多工程师的加入,面试难度也水涨船高。这不昨天有个同学找我说,上周去京东面试,一面就没过去被刷下来了,非常受打击。经过仔细交谈之后觉得他还是技术储备不够,对一些知识了解的不深,所以说他这次被刷的不亏,涨涨经验也是很好的。根据他的面试经过我整理一下题和答案,希望在金九银十能帮助大家。 本人在这里整理了20多家公司的面试题,以及各种关于Spring、Spring boot、Spring MVC、MyBatis、MySQL、JVM等知识点,如果有需要的小伙伴可以加

Spring boot 296

C语言实现惯导系统的间接粗对准

间接粗对准方法具有更好的角晃动抗干扰能力,只是在短时间内线晃动抗干扰能力相对弱些,若适当延长粗对准时间(一般在分钟量级),间接粗对准方法往往都能够取得良好的效果。间接粗对准方法是一种非常实用的捷联惯导粗对准方法,得到了广泛的应用。在惯导系统进入工作前,需要进行初始对准,使得惯导系统与当地导航坐标系指向一致,便于惯导系统更好地进入工作状态。博主利用C语言实现了间接粗对准,间接粗对准较之解析粗对准更有优势。以上函数中使用的其他函数块,已在之前或之后的博客中给出。

十八与她的博客 789

python爬取银行年报2

python爬取公司年报(巨潮资讯网)

bboysteed的博客 4731

面试官:并发编程实战会吗?(线程控制操作详解)

在使用Java实际编程中,多线程可以说是无所不在,凡是需要并发执行的都可以用到它,一个应用程序中不用多线程将会是很糟糕的事情,所以 掌握线程以及它的控制操作是非常重要的

Trouvailless的博客 301

2020年大连理工大学《计算机控制技术》期末试卷

2020年大连理工大学《计算机控制技术》期末试卷 2020年大连理工大学《计算机控制技术》期末试卷 2020年大连理工大学《计算机控制技术》期末试卷 2020年大连理工大学《计算机控制技术》期末试卷 ...

无名何许人的博客 650

Java多线程常用面试题(含答案,精心总结整理)

Java并发编程问题是面试过程中很容易遇到的问题,提前准备是解决问题的最好办法,将试题总结起来,时常查看会有奇效。 现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行? 这个线程问题通常会在第一轮或电话面试阶段被问到,目的是检测你对”join”方法是否熟悉。这个多线程问题比较简单,可以用join方法实现。 核心: thread.Jo

山有多高的博客 12万+

全网首发--Unet3+改进16:在不同位置添加RepLKBlock超大卷积核

本文提出了一种基于大核卷积的神经网络架构RepLKNet,旨在缩小CNN与ViTs之间的性能差距。通过重新审视CNN中的大核设计,研究证明使用少量大卷积核替代多个小核能获得更强大的性能。提出的RepLKNet采用31×31大卷积核,在ImageNet和下游任务上取得了与SwinTransformer相当或更好的结果,同时具有更低延迟。文章详细介绍了实现步骤:(1)创建RepLKBlock模块文件;(2)在模型层中添加注意力机制;(3)在UNet模型中集成RepLKBlock;(4)完成训练流程。该方法展现了

AIcurator的博客 626

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

2020并发编程必学的面试题,我先学为敬你呢?

前言 由于资料太多,此篇文章限于篇幅只分享了小部分资料,如果需要全套并发真题的朋友(内含所有题目答案)请点击这里 暗号:qf 正题 1.现在有 T1、T2、T3 三个线程,你怎样保证 T2 在 T1 执行完后执行,T3 在 T2 执行完后执 行? 这个线程问题通常会在第一轮或电话面试阶段被问到,目的是检测你对”join”方法是否熟 悉。这个多线程问题比较简单,可以用 join 方法实现。 2.在 Java 中 Lock 接口比 synchronized 块的优势是什么? 你需要实现一个高效的缓存,它允 许

w1103576的博客 852

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

少走弯路就看这里,《浓缩的精髓:2020年并发编程面试题》

借用 Java 并发编程实践中的话:编写正确的程序并不容易,而编写正常的并发程序就更难了。相比于顺序执行的情况,多线程的线程安全问题是微妙而且出乎意料的,因为在没有进行适当同步的情况下多线程中各个操作的顺序是不可预期的。 并发编程相比 Java 中其他知识点学习起来门槛相对较高,学习起来比较费劲,从而导致很多人望而却步;而无论是职场面试和高并发高流量的系统的实现却都还离不开并发编程,从而导致能够真正掌握并发编程的人才成为市场比较迫切需求的。 正文 1)现在有 T1、T2、T3 三个线程,你怎样保证 T.

w1103576的博客 345

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

上一篇: Java 同步工具与组合类的线程安全性分析
下一篇: 聊聊 Java 数据结构与算法中的堆最小堆和最大堆
java_lujj
博客等级 码龄4年 18粉丝 152原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值