线程:
- 线程(英语:thread)是操作系统能够进行运算调度的最小单位。大部分情况下,它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。
- 线程是独立调度和分派的基本单位 ?
- 一个进程可以有很多线程,每条线程并行执行不同的任务。
同一进程中的多条线程将共享该进程中的全部系统资源,如虚拟地址空间,文件描述符和信号处理等等。但同一进程中的多个线程有各自的调用栈(call stack),自己的寄存器环境(register context),自己的线程本地存储(thread-local storage)。
多线程
多线程(英语:multithreading),是指从软件或者硬件上实现多个线程并发执行的技术。具有多线程能力的计算机因有硬件支持而能够在同一时间执行多于一个线程,进而提升整体处理性能。具有这种能力的系统包括对称多处理机、多核心处理器以及芯片级多处理(Chip-level multithreading)或同时多线程(Simultaneous multithreading)处理器。
线程池
线程池(英语:thread pool):一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。 例如,线程数一般取cpu数量+2比较合适,线程数过多会导致额外的线程切换开销。
任务调度以执行线程的常见方法是使用同步队列,称作任务队列。池中的线程等待队列中的任务,并把执行完的任务放入完成队列中。
线程池模式一般分为两种:HS/HA半同步/半异步模式、L/F领导者与跟随者模式。半同步/半异步模式又称为生产者消费者模式,是比较常见的实现方式,比较简单。分为同步层、队列层、异步层三层。同步层的主线程处理工作任务并存入工作队列,工作线程从工作队列取出任务进行处理,如果工作队列为空,则取不到任务的工作线程进入挂起状态。由于线程间有数据通信,因此不适于大数据量交换的场合。
- 领导者跟随者模式,在线程池中的线程可处在3种状态之一:领导者leader、追随者follower或工作者processor。任何时刻线程池只有一个领导者线程。事件到达时,领导者线程负责消息分离,并从处于追随者线程中选出一个来当继任领导者,然后将自身设置为工作者状态去处置该事件。处理完毕后工作者线程将自身的状态置为追随者。这一模式实现复杂,但避免了线程间交换任务数据,提高了CPU cache相似性。在ACE(Adaptive Communication Environment)中,提供了领导者跟随者模式实现。
线程池的伸缩性对性能有较大的影响。
- 创建太多线程,将会浪费一定的资源,有些线程未被充分使用。
- 销毁太多线程,将导致之后浪费时间再次创建它们。
- 创建线程太慢,将会导致长时间的等待,性能变差。
- 销毁线程太慢,导致其它线程资源饥饿。
进程
进程(英语:process),是指计算机中已运行的程序。进程曾经是分时系统的基本运作单位。在面向进程设计的系统(如早期的UNIX,Linux 2.4及更早的版本)中,进程是程序的基本执行实体;在面向线程设计的系统(如当代多数操作系统、Linux 2.6及更新的版本)中,进程本身不是基本运行单位,而是线程的容器。程序本身只是指令、数据及其组织形式的描述,进程才是程序(那些指令和数据)的真正运行实例。若干进程有可能与同一个程序相关系,且每个进程皆可以同步(循序)或异步(平行)的方式独立运行。现代计算机系统可在同一段时间内以进程的形式将多个程序加载到存储器中,并借由时间共享(或称时分复用),以在一个处理器上表现出同时(平行性)运行的感觉。同样的,使用多线程技术(多线程即每一个线程都代表一个进程内的一个独立执行上下文)的操作系统或计算机体系结构,同样程序的平行线程,可在多CPU主机或网络上真正同时运行(在不同的CPU上)。协程
与子例程一样,协程也是一种程序组件。相对子例程而言,协程更为一般和灵活,但在实践中使用没有子例程那样广泛。协程源自Simula和Modula-2语言,但也有其他语言支持。协程更适合于用来实现彼此熟悉的程序组件,如合作式多任务,迭代器,无限列表和管道。
Java 多线程脑图(总览)
一、Java多线程基础知识
- Java多线程介绍
- 多线程入门
- 线程创建与启动以及线程状态
- Runnable接口详细详解
- 线程优先级以及守护线程详解
- 线程同步
- 线程间通讯
- 线程组详解
- 自动运行对象详解
- 线程异常回调
- 线程池详解
- 等待线程完成任务
- 阻塞IO和多线程详解
- 如何优雅的结束线程
- 自定义线程锁详解
- FIFO队列与线程
-
二、多线程设计模式详细介绍
多线程内容回顾
- waitSet概念介绍
- 多线程程序衡量标准讨论
- Single Thread Excution 模式介绍
- 不可变对象以及线程安全对象介绍
- Guraded Suspension 模式讲解
- Balking 模式详细介绍
- Producer-Consumer设计模式介绍
- 读写锁设计模式详细介绍
- Thread-Per-Message 模式详细介绍
- worker 模式详细介绍
- Future 设计模式详细介绍
- Two-Phase Termination 设计模式详细介绍
- Thread-Specific Stoage 模式详细介绍
- Avtive Object -接受异步消息的主动对象
-
三、JDK开发包详解介绍
原子变量
- Unsafe
- CountDownLatch
- CyclicBarrier
- Exchanger
- ExecutorService
- Phaser
- 显示锁
- ReetrantLock
- ReadWriteLock
- StamedLock
- Condition
- Semaphore 信号量
- ForkJoin 框架
- 并发容器
- ConcurrentHashMap
- ConcurrentLikedDeque
- ConcurrentSkipMap
- ConcurrentSkipSet
- CopyOnWriteArrayList
- CopyOnWriteArraySet
- DelayQueue
- LikedBlockingDeque
- LikedBlockingQueue
- LikedTransferQueue
- PriontyBlockingQueue
- CompletableFuture
自定义并发类
死锁诊断,JVM工具,线程堆栈介绍
- 线程安全性探讨
- 数据共享,以及数据共享带来的安全隐患
- 构建线程安全类,选择优化策略
- 构建并行模块基础讲解
- 执行并行热舞详细介绍
- 任务的执行与关闭
- 线程池的优化
- 线程上下文,性能,可伸缩性探讨
- 多线程中的锁详细讲解
- 构建同步工具
- 原子变量与非阻塞同步机制
- goole Concurrent 包介绍
- goole EventBus包介绍
一.进程和线程的区别
1.进程之间共享信息可以通过tcp/ip协议,线程间共享信息可以通过公用内存
2.进程是OS分配资源的基本单位,线程是执行调度的基本单位
3.进程是抢占处理器的调度单位,线程属于某个进程,共享其资源
4.进程是程序的多个顺序的流动态执行
5.线程没有自己独立的地址空间,多进程的程序比多线程的程序健壮
6.进程的切换比线程的切换开销大
纤程:用户态的线程,线程中的线程,切换和调度不需要经过OS
优势:1:占用的资源很少·2.切换比较简单3.可以启动很多个10w+
二.Java进程和线程的关系
1.Java对操作系统提供的功能进行封装,包括进程和线程
2.运行一个程序会产生一个进程,进程包含至少一个线程
3.每个进程对应一个JVM实例,多个线程共享JVM里的堆
4.Java采用单线程编程模型,程序会自动创建主线程
5.主线程可以创建子线程,原则上要后于子线程完成执行
三.多线程的三种创建方式
在JAVA中创建一个线程:
如果调用T1的run()方法,那就是简单的方法调用,代码还是在main线程中从上到下依次执行;
如果调用T1的start()方法,则会开启一个新的线程(记为thread1)执行,那么thread1和main线程同时执行,表现为控制台”T1”和”main”交替输出.
public class T01_WhatIsThread {
private static class T1 extends Thread {
@Override
public void run() {
for(int i=0; i<10; i++) {
try {
TimeUnit.MICROSECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("T1");
}
}
}
public static void main(String[] args) {
//new T1().run();
new T1().start();
for(int i=0; i<10; i++) {
try {
TimeUnit.MICROSECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main");
}
}
}
2:Thread 2: Runnable 3:Executors.newCachedThrad (lamda 表达式)
public class T02_HowToCreateThread {
static class MyThread extends Thread {
@Override
public void run() {
System.out.println("Hello MyThread!");
}
}
static class MyRun implements Runnable {
@Override
public void run() {
System.out.println("Hello MyRun!");
}
}
public static void main(String[] args) {
// 第一种,对象继承Thread,然后直接new该对象
new MyThread().start();
// 第二种,对象实现Runnable,该对象作为参数创建一个Thread对象
new Thread(new MyRun()).start();
// 第二种的变式,其实是匿名内部类的实例作为实现Runnable的对象,又加了lambda表达式简化代码
new Thread(()->{
System.out.println("Hello Lambda!");
}).start();
// 第三种线程池Executors.newCachedThrad等,其实最终实现也是前两种之一
}
}
四. 线程的常见操作
前言
CPU只管执行命令,对于CPU来说,没有线程的概念,它只是不断的从内存中去拿取指令去执行.
多线程呢,就是有好多个线程竞争着去给CPU发送命令,每个线程上的命令在CPU上执行一小会,多个线程的命令快速交替执行,这样看起来像是同时执行的.
各个线程和CPU之间,相当于有一个”等待队列”,线程们在队列中排队,等着CPU从队列中随机找一个线程去执行;CPU执行某个线程的一小段命令后,不等执行完,就把它扔回等待队列,然后重新找一个线程执行,这样快速的切换感觉像是多个线程同时执行.如果线程执行完了,那就终结了自己的一生,不会再进入等待队列了.
线程操作:
sleep(long millis):当前线程休息一定毫秒数,把执行命令的机会让给其他线程,睡够一定时间后进入等待队列,继续竞争CPU的执行机会
yield():当前线程正在CPU上运行时,先退出一下,进去线程等待队列,然后大家再一起公平竞争CPU的执行机会.这个几乎用不到.
join():假设俩个线程t1,t2,在t1中调用t2.join(),则此时执行t2的命令,t2执行完后t1继续执行,用于保证线程的执行顺序
stop(): 在工程中尽量不要用,容易出现状态不一致问题,略复杂,就当没有这个方法吧
interrupt():interrupt后会抛出一个异常,需要在上层catch改异常,然后做一些逻辑处理,控制程序流程.业务逻辑中也几乎没有必须interrupt的,也尽量不要用.
假想的一个interrupt的场景:线程t1调用了sleep(两天)的方法,但是在一天后,需要让它醒来,那就调用t1.interrupt();前提是t1sleep时做好被interrupt的准备,即catchinterrupted异常,然后继续执行或者干点别的事.
线程的常见状态
线程状态迁移图:
线程在”等待队列”中等着被CPU执行时,就是Ready状态;线程正在被CPU执行时,是Running状态;Ready和Running合称为Runnable状态.
线程执行完后(或者被操作系统kill掉),进入terminated状态,结束了自己的一生,啥都不能干了(等待被GC回收).
获取线程状态的方法:new MyThead().getState();