文章目录
Java并发编程基础
什么是线程:
现代操作系统运行一个程序时,会为其创建一个线程。
一个进程里可以创建多个线程,这些线程都拥有各自的计数器,堆栈和局部变量等属性,并且能够访问共享的内存变量。处理器在这些线程上高速切换,让使用者感觉到这些线程在同时进行。
线程优先级
Java线程中通过整体成员变量priority去控制优先级,优先级的范围从1-10,默认是5,可以通过setPriority去改变。但是,有时候操作系统会忽略这个对线程优先级的设置。
线程的状态
正常在操作系统中线程有5个状态:
java中则多了一种,一共六种,new, runnable, blocked, watting, time_wating, terminated
状态名 | 说明 |
---|---|
NEW | 初始状态,线程被创建,但是没有调用start() |
RUNNABLE | 运行状态,Java线程将操作系统中的就绪和运行两种状态笼统的称为:运行中 |
BLOCKED | 阻塞状态,表示线程阻塞于锁 |
WAITING | 等待,线程需要别的线程的一个动作或者消息,比如通知或者中断 |
TIME_WAITING | 有时间的,比如sleep啊,wait(time),过了一定时间就可以返回的 |
TERMINATED | 终止,已经执行完毕 |
Daemon线程
一种支持型线程,因为它主要被用作程序中后台调度以及支持型工作,这意味着,当一个Java虚拟机中不存在非Deamon线程时,Java虚拟机会退出,这时候finally块不一定会执行。
ps:在构建Daemon线程时,不能依靠finally块中的内容来确保执行关闭或被清理
启动或终止线程
使用线程之前需要构建一个线程对象。
Thread parent = currentThread();
group;
daemon;
name;
targer;
priority;
启动线程
thread.start();
理解中断
Thread.interrupted()
thread.isInterupted()
上述两个方法很不一样,第一个会使得interrupt标记复位,在一些抛出Interrupted的方法比如sleep,在抛出interruptException之前,java虚拟机先会把他们的中断标志位清楚(在一个sleep的线程使用interrupt,是没有用的,会抛出interruptException)
安全地终止线程
中断是一个简单的线程间的交互方法,这样可以用来取消或者停止任务。、
还有一个其他方法可以使用,就是用boolean变量。
public class ShutDown {
public static void main(String[] args) throws Exception {
Runner one = new Runner();
Thread countThread = new Thread(one, "CountThread");
countThread.start();
TimeUnit.SECONDS.sleep(1);
Runner two = new Runner();
countThread = new Thread(two, "CountThread");
TimeUnit.SECONDS.sleep(1);
two.cancel();
}
private static class Runner implements Runnable {
private long i;
private volatile boolean on = true;
@Override
public void run() {
while (on && Thread.currentThread().isInterrupted) {
i ++;
}
sout("count = i:" + i);
}
public void cancel() {
on = false;
}
}
}
这就是一种很优雅的方式,让线程中断的时候有机会去清理资源
线程间通信
volatile和synchronized关键字
volatile写和volatile读
synchronized释放锁和获得锁,这就是一对线程间通信的方案。
synchronized
使用了monitorenter 和monitorexit指令,这对monitor指令就完成一个通信。
先去enter,enter成功了就获得监视器。失败了就滚去排队,再等待别人离开监视器。
等待/通知机制
notify(), notifyAll(), wait(), wait(long), wait(long, int)
一个线程调用了对象O的wait方法后进入等待状态, 当另一个线程调用了O的notify()方法, 那么收到这个通知的线程就会从等待状态返回,再执行一遍这个操作。
等待通知机制的经典范式
- 获得对象的锁
- 如果条件不满足,就调用对象的wait()方法,被通知后仍要检查条件
- 条件满足再执行对应的逻辑
synchronized(对象){
while(条件不满足) {
对象.wait();
}
对象处理
}
通知:
- 获得对象的锁
- 改变条件
- 通知所有等待着的线程
synchronized(对象) {
改变条件
对象.notifyAll();
}