Java 线程基础、线程之间的共享和协作 (五)
AQS (AbstractQueuedSynchronizer简称 )
队列同步器AbstractQueuedSynchronizer(以下简称同步器或AQS),是用来构建锁或者其他同步组件的基础框架,它使用了一个int成员变量表示同步状态,通过内置的FIFO队列来完成资源获取线程的排队工作。
定义:假定有两个操作A和B(A和B可能都很复杂),如果从执行A的线程来看,当另一个线程执行B时,要么将B全部执行完,要么完全不执行B,那么A和B对彼此来说是原子的。
实现原子操作可以使用锁,锁机制,满足基本的需求是没有问题的了,但是有的时候我们的需求并非这么简单,我们需要更有效,更加灵活的机制,
实现原子操作还可以使用当前的处理器基本都支持CAS()的指令,只不过每个厂家所实现的算法并不一样,每一个CAS操作过程都包含三个运算符:一个内存地址V,一个期望的值A和一个新值B,操作的时候如果这个地址上存放的值等于这个期望的值A,则将地址上的值赋为新值B,否则不做任何操作。
- 初始(NEW):新创建了一个线程对象,但还没有调用start()方法。
- 运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。
线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。- 阻塞(BLOCKED):表示线程阻塞于锁。
- 等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。
- 超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。
- 终止(TERMINATED):表示该线程已经执行完毕。
状态之间的变迁如下图所示
进程是程序运行资源分配的最小单位
线程是 CPU 调度的最小单位,必须依赖于进程而存在
核心数、线程数:目前主流 CPU 都是多核的。增加核心数目就是为了增加线 程数,因为操作系统是通过线程来执行任务的,一般情况下它们是 1:1 对应关系,也 就是说四核 CPU 一般拥有四个线程。但 Intel 引入超线程技术后,使核心数与线程 数形成 1:2 的关系
时间片轮转调度是一种最古老、最简单、最公平且使用最广的算法,又称 RR 调度。每个进程被分配一个时间段,称作它的时间片,即该进程允许运行的时间。
并发:指应用能够交替执行不同的任务,比如单 CPU 核心下执行多线程并非是 同时执行多个任务,如果你开两个线程执行,就是在你几乎不可能察觉到的速度不 断去切换这两个任务,已达到”同时执行效果”,其实并不是的,只是计算机的速度太 快,我们无法察觉到而已.
并行:指应用能够同时执行不同的任务,例:吃饭的时候可以边吃饭边打电话, 这两件事情可以同时执行 两者区别:一个是交替执行,一个是同时执行.
当谈论并发的时候一定要加个单位时间,也就是说单位时间内并发量是多少? 离开了单位时间其实是没有意义的。
泛型的好处
- 代码更健壮(编译器警告,不会出现ClassCastExceptiion);
- 代码更加简洁(不用强转);
- 代码更灵活,复用。
1 | public class Test<T>{ |
1 | //定义一个泛型接口 |
1 |
|
1 | class Student implements Person<String>{ |
1 | /** |
1 | public <T> T get(Class<T> tClass){ |