Java多线程编程笔记一
并发编程基础
什么是线程?
进程:是并发执行的程序在执行过程中分配和管理资源的基本单位,是一个动态概念,竞争计算机系统资源的基本单位。
线程:是进程的一个执行单元,是进程内可调度实体。比进程更小的独立运行的基本单位。线程也被称为轻量级进程。
一个进程有多个线程,多个线程共享进程的堆和方法区资源,但是每个线程有自己的程序计数器和栈区域。
线程的栈区域:存储该线程的局部变量、存放线程的调用栈帧,其他线程访问不了。
进程的堆区域:堆,是进程最大的一块内存,被所有线程所共享;主要存放 new 操作创建的对象实例。
方法区:存在 JVM 加载的类、常量及静态变量等,是线程共享的。
如何创建线程?
实现 Runnable 接口
--实现 run() 方法 无返回值,无参数,难以传参;
继承 Thread 类
--实现 run() 方法 无返回值,无参数,由于继承特性,便于传参;
实现 Callable 接口
--实现 call 方法 有返回值,可由 FutureTask<t> 类型变量接收结果,无参数,难以传参。结果通过 FutureTask 对象的 get() 方法获取。</t>
Object 类作为共享资源的相关实例方法
wait(); 当一个共享变量的 wait() 方法被调用时,该调用线程会被阻塞挂起,直到
(1).其他线程调用的该共享变量的 notify() 或 notifyAll() 方法唤醒;
(2).其他线程调用了此线程的 interrupt() 方法,使此线程抛出异常而返回;
wait(long timeout); 执行此方法后,若该线程未在规定时间类被其他线程唤醒,则会抛出异常返回。
wait(long timeout , int nanos); 当 0 < nanos <999999 ,timeout 增加 1;
notify() 与 notifyAll(); 共享变量调用后,唤醒 一个/所有 被 wait 阻塞的线程,不放资源;
Thread 类相关方法
获取当前的 Thread实例 Thread.currentThread();
join(); 等待线程执行结束的方法。
static sleep(); 当前线程等待时间后继续执行,不放 CPU;
static yield(); 当前线程礼让,然后一起参与对 CPU 的竞争;
void interrupt(); 将此线程标记为被中断状态的线程
boolean isInterrupted();检测是否被标记为中断状态
static boolean interrupted();检测,且若检测出中断状态,将会清除中断标记;
死锁
死锁是指两个或两个以上的线程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象。
死锁产生的条件:
互斥条件:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。
请求和保持条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。
不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
环路等待条件:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个 P1 占用的资源; P1 正在等待 P2 占用的资源,……, Pn 正在等待已被 P0。
能够打破的死锁条件为 请求并持有条件 与 环路等待条件。
守护线程与用户线程
ThreadLocal 与 InheritableThreadLocal
当使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
void set(T value);设置当前线程的线程局部变量的值。
public T get();该方法返回当前线程所对应的线程局部变量。
public void remove();将当前线程局部变量的值删除,目的是为了减少内存的占用,该方法是JDK 5.0新增的方法。需要指出的是,当线程结束后,对应该线程的局部变量将自动被垃圾回收,所以显式调用该方法清除线程的局部变量并不是必须的操作,但它可以加快内存回收的速度。
protected T initialValue();返回该线程局部变量的初始值,该方法是一个protected的方法,显然是为了让子类覆盖而设计的。这个方法是一个延迟调用方法,在线程第1次调用get()或set(Object)时才执行,并且仅执行1次。ThreadLocal中的缺省实现直接返回一个null。
ThreadLocal是如何做到为每一个线程维护变量的副本的呢?
在ThreadLocal类中有一个Map,用于存储每一个线程的变量副本,Map中元素的键为线程对象,而值对应线程的变量副本。
对于多线程资源共享的问题,同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式。前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问而互不影响。
ThreadLocal 不具继承想,InheritableThreadLocal继承自ThreadLocal,能够解决ThreadLocal不能访问父线程地方变量的问题。
(学习笔记)