线程与进程

  • 进程:用来加载指令、管理内存、管理IO。操作系统会以进程为单位,分配系统资源(CPU时间片、内存等资源),进程是资源分配的最小单位。
  • 线程:有时被称为轻量级进程(Lightweight Process,LWP),是操作系统调度(CPU调度)执行的最小单位。

进程间通信的方式

  • 管道(pipe)及有名管道(named pipe):管道可用于具有亲缘关系的父子进程间的通信,有名管道除了具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。
  • 信号(signal):信号是在软件层次上对中断机制的一种模拟,它是比较复杂的通信方式,用于通知进程有某事件发生,一个进程收到一个信号与处理器收到一个中断请求效果上可以说是一致的。
  • 消息队列(message queue):消息队列是消息的链接表,它克服了上两种通信方式中信号量有限的缺点,具有写权限的进程可以按照一定的规则向消息队列中添加新信息;对消息队列有读权限的进程则可以从消息队列中读取信息。
  • 共享内存(shared memory):可以说这是最有用的进程间通信方式。它使的多个进程可以访问同一块内存空间,不同进程可以及时看到对方进程中对共享内存中数据的更新。这种方式需要依靠某种同步操作,如互斥锁和信号量等。
  • 信号量(semaphore):主要作为进程之间及同一种进程的不同线程之间的同步和互斥手段。
  • 套接字(socket):这是一种更为一般的进程间通信机制,它可用于网络中不同机器之间的进程间通信,应用非常广泛。

线程的同步互斥

  • 线程同步:线程之间所具有的一种制约关系,一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直到消息到达时才被唤醒。
  • 线程互斥:对于共享的进程系统资源,在各单个线程访问时的排它性。

线程同步互斥的控制方法

  • 临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。(在一段时间内只允许一个线程访问的资源就称为临界资源)。
  • 互斥量:为协调共同对一个共享资源的单独访问而设计的。
  • 信号量:为控制一个具有有限数量用户资源而设计。
  • 事件:用来通知线程有一些事件已发生,从而启动后继任务的开始。

线程上下文切换(Context switch):一般要5-10毫秒

  • 下文切换是指CPU(中央处理单元)从一个进程或线程到另一个进程或线程的切换。
  • 是多任务操作系统的一个基本特性。
  • 切换的耗时一般为5-10毫秒。
  • 上下文切换只能在内核模式下发生!

操作系统层面线程状态:初始状态、可运行状态、运行状态、休眠状态和终止状态。

  • 初始状态:指的是线程已经被创建,但是还不允许分配 CPU 执行。
  • 可运行(就绪)状态:指的是线程可以分配 CPU 执行。在这种状态下,真正的操作系统线程已经被成功创建了,所以可以分配 CPU 执行。
  • 运行状态:获取到CPU的时间片。
  • 休眠状态:运行状态的线程如果调用一个阻塞的 API(例如以阻塞方式读文件)或者等待某个事件(例如条件变量),那么线程的状态就会转换到休眠状态,同时释放 CPU 使用权,休眠状态的线程永远没有机会获得 CPU 使用权。
  • 终止状态:线程执行完或者出现异常就会进入终止状态,终止状态的线程不会切换到其他任何状态,进入终止状态也就意味着线程的生命周期结束了。

java的线程状态

  • 取自Thread类的内部枚举
    public enum State {// 初始化状态NEW,// 可运行状态+运行状态RUNNABLE,// 阻塞状态BLOCKED,// 无时限等待WAITING,// 有时限等待TIMED_WAITING,// 终止状态TERMINATED;}

面试中问你线程的状态,你应该如何回答?

  • 在操作系统层面有5种,java中有6种。
  • Java线程中的 BLOCKED、WAITING、TIMED_WAITING 是一种状态,即操作系统的休眠状态。这三种状态永远没有CPU的使用权!
  • Java线程中的 RUNNABLE 状态,在操作系统中分为:可运行(就绪)状态、运行状态。

Java线程的实现方式(4种)

  • 使用 Thread类或继承Thread类
// 创建线程对象
Thread t = new Thread() {public void run() {// 要执行的任务}
};
// 启动线程
  • 实现 Runnable 接口配合Thread:线程(Thread)与任务(Runnable)分开
Runnable runnable = new Runnable() {public void run(){// 要执行的任务}
};
// 创建线程对象
Thread t = new Thread( runnable );
// 启动线程
  • 使用有返回值的 Callable
class CallableTask implements Callable<Integer> {@Overridepublic Integer call() throws Exception {return new Random().nextInt();}
}
//创建线程池
ExecutorService service = Executors.newFixedThreadPool(10);
//提交任务,并用 Future提交返回结果
  • 使用 lambda
new Thread(() -> System.out.println(Thread.currentThread().getName())).start();

Thread常用方法

sleep方法

  • 调用 sleep 会让当前线程从 Running 进入TIMED_WAITING状态,不会释放对象锁
  • 其它线程可以使用 interrupt 方法打断正在睡眠的线程,这时 sleep 方法会抛出 InterruptedException,并且会清除中断标志
  • 睡眠结束后的线程未必会立刻得到执行
  • sleep当传入参数为0时,和yield相同

yield方法

  • yield会释放CPU资源,让当前线程从 Running 进入 Runnable状态,让优先级更高(至少是相同)的线程获得执行机会,不会释放对象锁;
  • 假设当前进程只有main线程,当调用yield之后,main线程会继续运行,因为没有比它优先级更高的线程;
  • 具体的实现依赖于操作系统的任务调度器

join方法

  • 等待调用join方法的线程结束之后,程序再继续执行,一般用于等待异步线程执行完结果之后才能继续运行的场景。

如何正确优雅的停止线程?

stop方法

  • stop()方法已经被jdk废弃,原因就是stop()方法太过于暴力,强行把执行到一半的线程终止。

Java线程的中断机制

  • 中断机制是一种协作机制,也就是说通过中断并不能直接终止另一个线程,而需要被中断的线程自己处理。
  • 被中断的线程拥有完全的自主权,它既可以选择立即停止,也可以选择一段时间后停止,也可以选择压根不停止。
  • interrupt(): 将线程的中断标志位设置为true,不会停止线程
  • isInterrupted(): 判断当前线程的中断标志位是否为true,不会清除中断标志位
  • Thread.interrupted():判断当前线程的中断标志位是否为true,并清除中断标志位,重置为fasle
  • sleep可以被中断 抛出中断异常:sleep interrupted, 清除中断标志位
  • wait可以被中断 抛出中断异常:InterruptedException, 清除中断标志位

Java线程间通信方式

  • volatile:两大特性,一是可见性,二是有序性,禁止指令重排序,其中可见性就是可以让线程之间进行通信。
  • 等待唤醒(等待通知)机制:基于wait和notify方法来实现,在一个线程内调用该线程锁对象的wait方法,线程将进入等待队列进行等待直到被唤醒。
  • LockSupport:JDK中用来实现线程阻塞和唤醒的工具,线程调用park则等待“许可”,调用unpark则为指定线程提供“许可”。
  • 管道输入输出流:PipedOutputStream、PipedInputStream、PipedReader和PipedWriter,前两种面向字节,而后两种面向字符。
  • Thread.join:可以简单理解为线程合并。一个线程等待到另一个线程执行完。

为什么说本质上Java中实现线程只有一种方式?

private Runnable target;@Overridepublic void run() {if (target != null) {target.run();}}
  • 继承Thread类,其实就是使用的Runnable对象调用run方法
public interface ThreadFactory {Thread newThread(Runnable r);
}
  • 线程池的创建,本质上也是传入一个Runnable对象
  • 使用lambda的方式,本质与继承的方式一致
  • 所以,创建线程的本质只有一种!

简单了解start()方法是如何开启一个线程的(JVM与操作系统层面)?

  • 使用new Thread()创建一个线程,然后调用start()方法进行java层面的线程启动;
  • 调用本地方法start0(),去调用jvm中的JVM_StartThread方法进行线程创建和启动;
  • 调用new JavaThread(&thread_entry, sz)进行线程的创建,并根据不同的操作系统平台调用对应的os::create_thread方法进行线程创建;
  • 新创建的线程状态为Initialized,调用了sync->wait()的方法进行等待,等到被唤醒才继续执行thread->run();
  • 调用Thread::start(native_thread);方法进行线程启动,此时将线程状态设置为RUNNABLE,接着调用os::start_thread(thread),根据不同的操作系统选择不同的线程启动方式;
  • 线程启动之后状态设置为RUNNABLE, 并唤醒第4步中等待的线程,接着执行thread->run()的方法;
  • JavaThread::run()方法会回调第1步new Thread中复写的run()方法。

结束语

  • 获取更多有价值的文章,让我们一起成为架构师!
  • 关注公众号,可以让你逐步对MySQL以及并发编程有更深入的理解!
  • 这个公众号,无广告!!!每日更新!!!

【并发编程:线程池】深入简出的带你精通java线程相关推荐

  1. java线程池案例_使用Executors 和 ThreadPoolExecutor实现Java线程池案例

    并发主题 使用Executors 和 ThreadPoolExecutor实现Java线程池案例 首先需要一个工作线程: package com.journaldev.threadpool; publ ...

  2. java 查询线程池_[代码全屏查看]-我的 Java 线程池测试类

    [1].[代码] TestThreadPool.java package net.oschina.tester; import java.io.Serializable; import java.ut ...

  3. 学习笔记(33):Python网络编程并发编程-进程池线程池

    立即学习:https://edu.csdn.net/course/play/24458/296451?utm_source=blogtoedu 进程池与线程池: 一般应用在网站上,进程池或线程池最大的 ...

  4. 【Java 并发编程】线程池机制 ( 线程池执行任务细节分析 | 线程池执行 execute 源码分析 | 先创建核心线程 | 再放入阻塞队列 | 最后创建非核心线程 )

    文章目录 一.线程池执行任务细节分析 二.线程池执行 execute 源码分析 一.线程池执行任务细节分析 线程池执行细节分析 : 核心线程数 101010 , 最大小成熟 202020 , 非核心线 ...

  5. java线程池原理简答_面试官让我讲讲Java线程池的实现原理,我笑了...

    期待与你,一起进步 随着cpu核数越来越多,不可避免的利用多线程技术以充分利用其计算能力.所以,多线程技术是服务端开发人员必须掌握的技术. 线程的创建和销毁,都涉及到系统调用,比较消耗系统资源,所以就 ...

  6. 线程池大小设置,CPU的核心数、线程数的关系和区别,同步与堵塞完全是两码事

    线程池应该设置多少线程合适,怎么样估算出来.最近接触到一些相关资料,现作如下总结. 最开始接触线程池的时候,没有想到就仅仅是设置一个线程池的大小居然还有这么多的学问,汗颜啊. 首先,需要考虑到线程池所 ...

  7. 别告诉我你连线程池都不会用~ 一文搞懂线程池

    线程池作用 降低资源消耗:通过池化技术重复利用已创建的线程,降低线程创建和销毁造成的损耗. 提高响应速度:任务到达时,无需等待线程创建即可立即执行. 提高线程的可管理性:线程是稀缺资源,如果无限制创建 ...

  8. DirectX12(D3D12)基础教程(十六)——实现渲染线程池:3个内核同步对象实现渲染线程池/大规模线程池

    文章目录 1.前言 2.深入了解MsgWaitForMultipleObjects()函数fWaitAll参数为TRUE时的问题 3.内核同步对象:CPU线程屏障(CPU Barrier)基础知识 4 ...

  9. 线程池很难么?带你从头到尾捋一遍,不信你听不懂!

    点击关注公众号,实用技术文章及时了解 来源:blog.csdn.net/qq_43061290/article/ details/106911277 目标 [理解]线程池基本概念 [理解]线程池工作原 ...

最新文章

  1. php内核探索方法与资源
  2. 面试高频题:单链表的逆置操作/链表逆序
  3. ServiceHot告诉你美国的程序员们各编程语言薪资情况
  4. PHP面试题:你常用到的mysql命令?
  5. mysql大数据更新缓存_redis缓存mysql
  6. 微服务四个常见问题,以及SpringCloud Netflix和SpringCloud Alibaba和Apache Dubbo zookeeper区别
  7. 使用Robotframework-ride,导入Selenium2Library库后缺少“Open Browser”关键字
  8. PHP在线网课问答题库搜索,推荐一个大学mooc网课答案题库在线查询公众号
  9. Spring-IoC注解
  10. svg基础+微信公众号交互(一)
  11. 供应链管理 | 华为是如何进行供应链规划与设计
  12. angular中布局文件中的#是什么意思?
  13. 【面试题记】删除字符串中相邻重复字符
  14. 怎样黑进Microsoft:循序渐进指南 (转)
  15. 海信JAVA开发笔试题_JAVA设计模式之【工厂方法模式】
  16. rmTopCMS——轻便、多变的CMS服务系统
  17. tomcat与servlet共存时报错 org.apache.catalina.LifecycleException:
  18. 【牛客】B 烦人的依赖(拓扑排序求顺序)
  19. 手机获取仪器数据_手机电子数据提取操作规范(20151120)
  20. 海关爬虫7代(圣佛版)

热门文章

  1. 这才是做生意的正确方法,360行,行行出状元,摆摊也能赚大钱
  2. android抖音loading动画,高仿抖音视频加载动画
  3. 原码补码相互转换,简单方法
  4. android 动态改变进度条,Android条纹进度条的实现(调整view宽度仿进度条)
  5. 如何创建一个安全的Docker基础镜像
  6. 赚四五百万,一款打卡作弊软件的 CEO 被判5年6个月!因破坏了钉钉系统获取用户真实地理位置...
  7. 《SpringBoot与Shiro整合-权限管理实战---从构建到模拟数据库登入》
  8. 使用nginx搭建HTTP FLV流媒体服务器
  9. opencv调pc摄像头拍摄图片
  10. 如何用memoQ实现DITA本地化?