一、进程和线程
进程:简单来说,一个进程就是一个正在执行的程序实例,包括程序计数器、寄存器、程序上下文等信息。进程是资源分配的最小单位,每个进程拥有自己的地址空间,因此当一个进程崩溃时,其他进程不会受到影响。
线程:线程又称为轻量级进程,是CPU调度的最小单位,对于同一个进程所拥有的多个线程是共享同一个地址空间的,因此一个线程崩溃很容易引起整个进程的崩溃。
二、进程间通信与同步
1、共享存储(通信)
共享存储就是在内存中开辟一段能被其他所有进程所访问的内存空间,并将其映射到一个值当中,通常有一个进程创建,而其他进程可以通过该值来映射到这段内存空间。
2、管道(通信)
管道是一种半双工的通信方式,数据只能单向流动,包括无名管道和有名管道,前者一般用于父子进程之间的通信,而后者可以用于任意进程之间的通信。
3、管程(同步)
管程是一个由过程、变量及数据结构等构成的一个集合,组成了一个特殊的模块,相当于一个类,对于任意时刻只能由一个进程进入管程当中,通过wait和signal(类似于Java中的wait和notify)原语来实现管城内进程的阻塞以及将管程外的另一进程调入其中。
4、信号量(同步)
信号量是一个计数器,用于记录对某个资源的存取状况,通过P、V操作来控制对资源状况的操作:
P:
(1)检查该资源是否正在被使用(信号量的值是否为正)
(2)如果信号量为正,则允许进程使用,信号量-1
(3)如果信号量为0,则不允许使用,该进程进入睡眠,直到信号量大于0时才唤醒
V:
当某个进程不再使用该信号量控制的资源时,将信号量+1,如果有进程正在等待该资源,则将其唤醒
5、互斥量(同步)
互斥量可以看成是只有1和0两个值的信号量,通常用来当作锁变量,1和0分别表示加锁和解锁。
6、消息传递(通信)
消息传递是一个进程给另外一个进程发送一条消息,而另外一个进程则从一个给定的源接受该消息的过程,如果没有消息可用,接收者可能会被阻塞,直到一条消息到达。通过send和receive两条原语控制消息发送和接收。
7、套接字(通信)
套接字通常用于不同机器上的进程进行通讯所用的方法,通常一个套接字由IP地址+TCP/UDP协议+端口port组成,socket建立连接的过程主要有服务器监听、客户端请求、连接确认三个阶段,之后通信双方就可以进行数据传输了。
三、线程间通信与同步
这里所说的线程间通信与同步一般是指同一个进程内部的线程之间的通信与同步,而同一个进程之间的线程共享同一个地址空间,所以线程间通信基本上就是利用了共享存储的思想就可以很方便的交换数据了,所以对于线程来说主要讨论的是其同步方式。
1、锁机制
通过各种锁机制如互斥锁、读写锁、分段锁等来控制不同线程对同一个资源的访问。
2、信号量
信号量用来控制同时访问某个特定资源的操作数量,或同时执行某个操作的数量、控制临界状态等。
3、闭锁
闭锁可以延迟线程的进度直到其到达中止状态,当闭锁到达某种状态之前,所有线程都不能通过,而到达该状态之后就会开放给所有线程通过,确保某些操作可以在另外一些操作全部完成后才开始。
4、屏障
屏障用于阻塞一组线程直到某个事件发生。闭锁用于等待某一事件,而屏障用于等待其他线程。
四、Java线程通信方法
1、锁变量
(1)Sychronized
内置锁,用管程实现,通过wait、notify/notifyAll方法实现线程等待和唤醒操作。
(2)ReentranLock
显示锁,底层采用乐观锁机制CAS算法实现。
2、信号量Semaphore
acquire方法即P方法,用于获取一个资源许可。
release方法即V方法,用于释放一个资源许可。
3、闭锁
(1)CountDownLatch
await方法用于等待计数器达到零,表示所有需要等待的事件都已发生。
countDown方法用于递减计数器,表示有一个事件发生。
(2)FutureTask
get方法用于获取任务状态,如果任务已经完成,则立即返回结果,否则将阻塞直到任务完成。
4、屏障
(1)CyclicBarrier
await方法用于线程到达屏障位置时调用,该方法将阻塞当前线程直到所有线程到达屏障位置。
(2)Exchanger
Exchange是一种两方(Two-Party)屏障,各个线程会在屏障位置交换数据。