进程与线程

进程,程序的一次执行过程,系统运行程序的基本单位。

启动main函数,即启动JVM的一个进程,mian函数为其主线程。

同类多个线程共享进程的堆和方法区资源,切换工作负担比进程小。

一个Java程序的运行时main线程和多个其他线程同时运行。

各个进程是独立的,但各个线程不一定,同一进程中线程会相互影响,线程执行开销小,但不利于资源的管理和保护。

线程私有:PC,虚拟机栈,本地方法栈

PC:改变PC读取指令,实现代码流程控制(字节码解释器);记录当前线程执行的位置(多线程)

native方法,记录undefined地址,Java代码,下一条指令的地址

PC线程私有,便于线程切换后恢复到正确位置

虚拟机栈:Java方法,栈帧在虚拟机栈出入栈

本地方法栈:Native方法,本地方法栈初入栈

保证线程中局部变量不被其他线程访问

堆和方法去(线程共享):

堆:存放新创建对象;方法区;存放类信息等

多线程好处:

线程切换和调度成本低,减少了上下文切换的开销;多个同类线程之间的资源竞争较小,任务执行效率提高

多线程带来的问题:

前文所讲,线程执行开销小,但不利于资源的管理和保护,内存泄漏,死锁,线程不安全(之后可详细讨论)

线程生命周期和状态:

只有六种,NEW,RUNNABLE,BLOCKED,WAITING,TIME_WAITING,TERMINATED,记忆时可以根据英文名称记忆

注意区分阻塞状态和等待状态。

RUNNABLE状态中包括运行中与就绪状态,当就绪状态的线程获得时间片后变称为运行状态(因时间分片粒度很小,因此不做状态区分了。

等待状态的线程需要依靠其他线程的通知才能够返回运行态,而超时等待的线程超过设置的时间后会自行返回到RUNNABLE状态;阻塞状态与锁有关,锁也是JAVA并发中的难点重点,后文会提及。

上下文切换:

上下文:线程执行过程中的运行条件和状态(PC,栈信息等)

线程切换上下文时需保留当前线程的上下文(当线程下次占用CPU时恢复现场),加载下一个将要占用CPU的线程的上下文

保存信息回复信息会占用CPU和内存资源,影响效率

线程死锁:

多个线程同时被阻塞,等待资源的释放,且占据着他们持有的资源(资源只能被一个线程占用)不释放(别的线程无法强行剥夺),形成了一种循环等待资源的关系

预防避免线程死锁:

破坏线程死锁的条件(一次性申请所有资源,主动释放占有的资源,按照某一顺序申请资源(银行家算法))

Java中的锁和监视器:

一直看到很多关于锁和监视器的字眼,这次好好了解一下。

  • Synchronization is built around an internal entity known as the intrinsic lock or monitor lock. (The API specification often refers to this entity simply as a "monitor.")
  • Every object has an intrinsic lock associated with it. By convention, a thread has to acquire the object's monitor lock before accessing them, and then release the monitor lock when it's done with them. A thread is said to own the lock between the time it has acquired the lock and released the lock. As long as a thread owns a monitor lock, no other thread can acquire the same lock. The other thread will block when it attempts to acquire the lock.
  • When a thread releases the lock, a happens-before relationship is established between that action and any subsequent acquisition of the same lock.

 

翻译:

同步(synchronized)是围绕一个内部实体建立的,被称为内在锁或监控锁。(API规范经常把这个实体简单地称为 "监视器")。
每个对象都有一个与之相关的内在锁。按照惯例,一个线程在访问对象之前必须获得对象的监控锁,然后在使用完后释放监控锁。一个线程在获得锁和释放锁这段时间内被称为拥有该锁。只要一个线程拥有一个监控锁,其他线程就不能获得相同的锁。当其他线程试图获取该锁时,它将阻塞。
当一个线程释放锁的时候,在这个动作和任何后续的相同锁的获取之间建立了一个发生在之前的关系。

这是官方文档里面的,但还是有些晦涩,我没太看懂