Java 中的线程池
Java 中的线程池合理地使用线程池可以带来以下三个主要好处:
降低资源消耗:通过重复利用已创建的线程,减少线程创建和销毁所造成的开销。
提高响应速度:当任务到达时,无需等待线程创建即可立即执行任务。
提高线程的可管理性:线程是稀缺资源,若无限制地创建线程,不仅会消耗系统资源,还会降低系统的稳定性。通过线程池,可以对线程进行统一分配、调优和监控。
线程池的实现原理
处理流程
判断核心线程池的线程是否都在执行任务:
如果没有,则创建一个新的工作线程来执行任务。
如果核心线程池的线程都在执行任务,则进入下一步。
判断工作队列是否已满:
如果工作队列未满,则将新提交的任务存储在工作队列中。
如果工作队列已满,则进入下一步。
判断线程池的线程是否都处于工作状态:
如果没有,则创建一个新的工作线程来执行任务。
如果线程池已满,则交给饱和策略来处理该任务。
ThreadPoolExecutor
execute 方法的执行流程ThreadPoolExecutor 在执行 execute 方法时,会根据以下四种情况进行处理:
如果当前运行的线程少于 corePoolSize,则创建 ...
Java 中的并发工具类
Java 中的并发工具类并发流程控制的手段
CountDownLatch
CyclicBarrier
Semaphore
在线程间交换数据的一种手段
Exchanger 工具类
CountDownLatch
CountDownLatch 允许一个或多个线程等待其他线程完成操作。
计数器必须大于等于 0,当计数器为 0 时,调用 await 方法不会阻塞当前线程。
CountDownLatch 不可能重新初始化或者修改 CountDownLatch 对象的内部计数器的值。
一个线程调用 countDown 方法 happen-before,另外一个线程调用 await 方法。
同步屏障 CyclicBarrier
CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。
让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。
每个线程调用 await 方法告诉 CyclicBarrier 我已经到达了屏障,然后当前线程被阻塞。
**CyclicBarrier 还提供一个更高级 ...
Java 中的 13 个原子操作类
Java 中的 13 个原子操作类原子更新基本类型类
AtomicBoolean:原子更新布尔类型。
AtomicInteger:原子更新整型。
int addAndGet(int delta):以原子方式将输入的数值与实例中的值(AtomicInteger 里的 value)相加。
int getAndIncrement():以原子方式将当前值加 1,注意,这里返回的是自增前的值。
void lazySet(int newValue):最终会设置成 newValue,使用 lazySet 设置值后,可能导致其他线程在之后的一小段时间内还是可以读到旧的值。
int getAndSet(int newValue):以原子方式设置为 newValue 的值,并返回旧值。
AtomicLong:原子更新长整型。
Atomic 包里的类基本都是使用 Unsafe 实现的
Unsafe 只提供了 3 种 CAS 方法:compareAndSwapObject、compareAndSwapInt 和 compareAndSwapLong。
看 AtomicBoolean 源码,发现它是先把 ...
Java 中的锁
Java 中的锁Lock 接口
锁是用来控制多个线程访问共享资源的方式,一般来说,一个锁能够防止多个线程同时访问共享资源(但是有些锁可以允许多个线程并发访问共享资源,比如读写锁)。
Lock 接口提供了与 synchronized 关键字类似的同步功能,只是在使用时需要显式地获取和释放锁。
Lock 接口拥有锁获取与释放的可操作性、可中断的获取锁以及超时获取锁等多种 synchronized 关键字所不具备的同步特性。
synchronized获取锁是一个原子操作,在线程获取锁的过程中是无法响应中断的。
队列同步器(AQS / AbstractQueuedSynchronizer)使用
AQS 用来构建锁或者其他同步组件的基础框架,它使用了一个 int 成员变量表示同步状态,通过内置的 FIFO 队列来完成资源获取线程的排队工作。
同步器自身没有实现任何同步接口,它仅仅是定义了若干同步状态获取和释放的方法来供自定义同步组件使用,同步器既可以支持独占式地获取同步状态,也可以支持共享式地获取同步状态。
方便实现 ReentrantLock、ReentrantReadWrite ...
Java并发编程基础
Java并发编程基础线程的状态
线程的状态变化
Daemon 线程
Daemon 线程是一种支持型线程(常被叫做守护线程),因为它主要被用作程序中后台调度以及支持性工作。
可以通过调用 Thread.setDaemon(true) 将线程设置为 Daemon 线程。
中断
许多声明抛出 InterruptedException 的方法(例如 Thread.sleep(long millis) 方法)在抛出 InterruptedException 之前,Java 虚拟机会先将该线程的中断标识位清除,然后抛出 InterruptedException。此时调用 isInterrupted() 方法将会返回 false。
安全地终止线程
使用标志位
使用中断
线程间通信
volatile 和 synchronized 关键字
等待/通知机制
难以确保及时性
难以降低开销
等待/通知的相关方法是任意 Java 对象都具备的,因为这些方法被定义在所有对象的超类 java.lang.Object 上。
不同线程之间通过锁对象的 wait 和 notify 方法进行消息 ...
Java内存模型
Java内存模型Java 内存模型的基础并发编程模型的两个关键问题
线程之间如何通信 / 线程之间如何同步
共享内存(Java采用):
线程之间共享程序的公共状态,通过写-读内存中的公共状态进行隐式通信。
同步是显式进行的。程序员必须显式指定某个方法或某段代码需要在线程之间互斥执行。
消息传递:
线程之间没有公共状态,线程之间必须通过发送消息来显式进行通信。
消息的发送必须在消息的接收之前,因此同步是隐式进行的。
Java 内存模型的抽象结构(JMM)
JMM 定义了线程和主内存之间的抽象关系:
线程之间的共享变量存储在主内存(Main Memory)。
每个线程都有一个私有的本地内存(Local Memory):
本地内存中存储了该线程以读/写共享变量的副本。
本地内存是 JMM 的一个抽象概念,并不真实存在。
从源代码到指令序列的重排序
为了提高性能,编译器和处理器常常会对指令做重排序。
编译器优化的重排序(编译器重排序):
编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。
指令级并行的重排序(处理器重排序):
现 ...
并发编程的挑战和底层原理
并发编程的挑战和底层原理并发编程的目的并发编程的目的是为了让程序运行得更快。
并发编程的挑战
上下文切换
死锁
资源限制
Java 并发机制的底层实现原理Java 中的并发机制依赖于 JVM 的实现和 CPU 的指令。
volatile 关键字
volatile 是轻量级的 synchronized,它在多处理器开发中保证了共享变量的“可见性”。
实现原理
对 volatile 变量进行写操作时,会多出第二行汇编代码:
将当前处理器缓存行的数据写回到系统内存。
这个写回内存的操作会使在其他 CPU 里缓存了该内存地址的数据无效。
volatile 的使用优化
将共享变量追加到 64 字节,保证每个缓存行中保留完整的一份数据,对于频繁修改的数据,可以有效提高多处理器的处理效率。
synchronized 关键字
锁对象
对于普通同步方法,锁是当前实例对象。
对于静态同步方法,锁是当前类的 Class 对象。
对于同步方法块,锁是 Synchronized 括号里配置的对象。
实现原理
JVM 基于进入和退出 Monitor 对象来实现方法同步和代码块同步:
任何对象都有 ...
消息队列-入门
基础概念消息队列是一个可以用于存放消息的容器
消息队列满足FIFO原则
参与消息传递的双方被称为生产者和消费者,生产者负责发送消息,消费者负责处理消息
消息队列是一种中间件
中间件是一种为应用软件服务的软件,不同的软件和技术架构可以借助中间件来实现信息与资源的共享
使用消息队列的优点:
异步处理提高系统性能(减少响应所需时间)
消峰/限流
降低系统耦合性
消峰/限流:
将短时间高并发的事务消息存储在消息队列中,之后后端服务再慢慢根据自己的能力去消费这些消息,可以避免直接把后端服务打垮掉
降低系统耦合性:
消息队列可以使用发布-订阅模式工作,生产者发布消息,一个或者多个消息接收者订阅消息。消息的生产者和消息的消费者之间没有直接的耦合。同时,如果希望新增消费者,只需要订阅该消息,对原有的系统和业务没有影响,提高系统的可拓展性。
实现分布式事务:
分布式事务的解决方案之一就是MQ事务。事务允许事件流应用将消费,处理,生产消息整个过程定义为一个原子操作
使用消息队列带来的问题:
导致系统可用性降低:消息队列可能挂掉
系统的复杂性提高:消息重复消费问题,处理 ...
操作系统-进程与线程
进程与线程进程与线程的概念
进程的概念:由 CPU 执行的运行中的程序,被称为进程 (Process)。
并行:两个任务同时进行。
并发:两个任务在一段时间中交替进行。
进程的状态
创建
就绪
就绪挂起
运行
阻塞
阻塞挂起
结束
进程的控制结构(PCB)
PCB 是进程存在的唯一标识:
进程描述信息:
进程标识符
用户标识符
进程控制和管理信息:
进程当前状态(new、ready、running、waiting、blocked)
进程优先级:进程抢占 CPU 时的优先级
资源分配清单:
包括内存地址空间和虚拟地址空间的信息,所打开的文件列表和所使用的 I/O 设备信息。
CPU 相关信息:
CPU 中各个寄存器的值,当进程被切换时,CPU 的状态信息都会保存在相应的 PCB 中。
进程的组织方式
链表:通过链表,把具有相同状态的 PCB 连接在一起,形成各种状态队列。
索引:把同一状态的进程组织在一个索引表中,索引表项指向对应的 PCB,不同状态对应不同的索引。
选择链表的原因
链表可以更灵活地进行插入和删除,适应进程的创建、销毁等调度需求。
...
操作系统-网络系统
网络系统网络性能指标
带宽:链路最大传输速率
延时:请求包发送后,收到对端响应所需要的时间延迟。不同场景含义不同,可以表示建立TCP连接所需要的时间延迟,或者一个数据包往返所需要的时间延迟。
吞吐量:单位时间成功传输的数据量
PPS:以网络包为单位的传输速度
其他指标
网络可用性
并发连接数
丢包率
重传率
查看网络配置的命令
ipconfig / ip
查看Socket信息
netstat / ss
查看网络吞吐量
sar
查看连通性和延时
ping
从日志分析PV、UV
ls -lh 查看文件大小
cat 查看文件,一次性加载
scp 传输文件到闲置的服务器
less 查看文件,部分加载
tail 查看文件最新内容
-n 指定行数
-f 实时刷新
wc -l 查看文件中行数
awk '{print substr($4, 2, 11) " " $1}' | sort | uniq | awk '{uv[$1]++; next}' END ...