进程和线程的基础知识
线程和进程的概念,并行和并发的概念
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。
线程,有时被称为轻量级进程(Lightweight Process,LWP),是程序执行流的最小单元。线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序的调度单位。在单个程序中同时运行多个线程完成不同的工作,称为多线程。
并行:多个线程可以同时执行,每一个时间段,可以有多个线程同时执行。
并发:多个线程同时竞争一个位置,竞争到的才可以执行,每一个时间段只有一个线程在执行。
创建线程的方式及实现
Java创建线程的方式主要有以下三种
- 继承Thread类
- 实现Runnable接口
- 实现Callable接口
- 创建继承自Thread类的子类并重写Thread类的run方法
- 通过创建该子类的对象,获得线程对象
- 调用线程对象的start()方法启动线程
- 定义Runnable接口的实现类并重写run()方法
- 创建实现类的对象,并以此Runnable对象作为Thread的target创建Thread对象,即线程对象
- 调用线程对象的start()方法启动线程
实现Callable接口
- 创建Callable接口的实现类并实现call()方法,该方法具有返回值
- 创建Callable实现类的对象,使用该Callable示例创建FutureTask的对象
- 以FutureTask对象作为Thread的target创建Thread对象,获得线程对象
- 调用线程对象的start()方法启动线程
- 调用FutureTask对象的get()方法获得线程运行结果
进程间通信的方式
进程间通信的方法主要有以下几种:
1. 管道 : 允许一个进程和另一个与它有共同祖先的进程之间进行通信
2.命名管道
3.信号 : 进程可以发送信号给进程本身
4.消息队列 : 客服了信号承载信息量少和管道只能承载无格式字节流以及缓冲区大小受到限制的缺点
5.共享内存 : 使得多个进程可以访问一个内存空间
6.内存映射 : 每一个使用该机制的进程通过把一个共享的文件映射到自己的进程地址空间来实现它
7.信号量 : 主要作为进程间以及同一进程不同线程之间的同步手段
8.套接口 : 更为一般的通信机制 ,可以用于不同机器之间的进程通讯
Java中我们实现多线程的通讯主要采用的是"共享变量"和"管道流"这两种方法
CountDownLatch、CyclicBarrier 原理和区别
CountDownLatch原理
CountDownLatch是使用一组线程来等待其它线程执行完成,这个场景类似于一群人考试,先做的人先交了,但是在考试时间没到的前提下,老师必须额等待最后一个学生完成交卷老师才能走,CountDownLatch使用Sync继承AQS。构造函数很简单地传递计数值给Sync,并且设置了state,这个state的值就是倒计时的数值,每当一个线程完成了自己的任务(学生完成交卷),那么就使用CountDownLatch.countdown()方法来做一次state的减一操作,在内部是通过CAS完成这个更新操作,直到所有的线程执行完毕,也就是说计数值变成0,那么就然后在闭锁上等待的线程就可以恢复执行任务。
CyclicBarrier原理 栅栏
CyclicBarrier 的字面意思是可循环(Cyclic)使用的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。线程进入屏障通过CyclicBarrier的await()方法。
实现原理:在CyclicBarrier的内部定义了一个Lock对象,其实就是ReenTrantLock对象,每当一个线程调用CyclicBarrier的await方法时,将剩余拦截的线程数减1,然后判断剩余拦截数是否为0,如果不是,进入Lock对象的条件队列等待。如果是,执行barrierAction对象的Runnable方法,然后将锁的条件队列中的所有线程放入锁等待队列中,这些线程会依次的获取锁、释放锁,接着先从await方法返回,再从CyclicBarrier的await方法中返回。
1.CountDownLatch的计数器只能使用一次。而CyclicBarrier的计数器可以使用reset() 方法重置。所以CyclicBarrier能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程们重新执行一次。
2.CyclicBarrier还提供其他有用的方法,比如getNumberWaiting方法可以获得CyclicBarrier阻塞的线程数量。isBroken方法用来知道阻塞的线程是否被中断。比如以下代码执行完之后会返回true。
其中await方法:1.获取lock对象,然后拦截数减一,直到拦截数为0,结束await
2.出现中断,结束栅栏然后退出
3.超时也可以退出栅栏
线程池的实现原理和实现方式
线程池就是创建多个线程并且进行管理的容器。(线程池是个容器,可以创建线程和管理线程,并且给线程分配任务)
线程池的好处:
重用已经存在的线程,减少了线程的创建和销毁的开销。(2)可有效控制最大并发的线程数,提高了系统资源的使用率避免很多竞争,避免了OOM啊 死锁啊等。(3)可以提供定时和定期的执行方式,单线程,并发数量的控制等功能!线程池可以使得对线程的管理更加方便,并且对高并发的控制尽在掌握。
fixedThreadPool() //启动固定线程数的线程池
CachedThreadPool() //按需分配的线程池
ScheduledThreadPoolExecutor()//定时,定期执行任务的线程池
ThreadPoolExecutor()//指定线程数的线程池
线程的声明周期
NEW:一个已创建而未启动的线程处于该状态。由于一个线程实例只能够被启动一次,因此一个线程只可能有一次处于该状态。
RUNNABLE:该状态可以被看成一个复合状态 。它包括两个子状态:READY 和 RUNNING。前者表示处于该状态的线程可以被线程调度器( Scheduler ) 进行调度而使之处于 RUNNING 状态 。后者表示处于该状态的线程正在运行,即相应线程对象的 run 方法 所对应的指令正在由处理器执行。执行Thread.yield()的线程,其状态可能会由RUNNING 转换为 READY。处于 READY 子状态的线程也被称为活跃线程。
BLOCKED:一个线程发起一个阻塞式I/O(Blocking I/O )操作后,或者申请一个由其他线程持有的独占资源(比如锁)时,相应的线程会处于该状态。处于BLOCKED 状态的线程并不会占用处理器资源。当阻塞式I/O操作完成后,或者线程获得了其申请的资源,该线程的状态又可以转换为RUNNABLE。
WAITING:一个线程执行了某些特定方法之后就会处于这种等待其他线程执行另外一些特定操作的状态。能够使其执行线程变更为 WAITING 状态的方法包括:Object.wait () 、 Thread.join()和 LockSupport.park(Object)。能够使相应线程从 WAITING 变更为 RUNNABLE 的相应方法包括 :Object.notify()/notify All()和 LockSupport. Unpark(Object)。
TIMED WAITING:该状态和WAITING 类似,差别在于处于该状态的线程并非无限制地等待其他线程执行特定操作,而是处于带有时间限制的等待状态。当其他线程没有在指定时间内执行该线程所期望的特定操作时,该线程的状态自动转换为RUNNABLE。
TERMINATED:已经执行结束的线程处于该状态。由于一个线程实例只能够被启动一次,因此一个线程也只可能有一次处于该状态。Thread.run()正常返回或者由于抛出异常而提前终止都会导致相应线程处于该状态。

浙公网安备 33010602011771号