自己整理的Java多线程学习笔记,顺便加深一下印象。
1 Daemon 线程 中run() 方法中的finally不一定会执行
2 如果线程在调用 sleep()方法前被中断,那么该中断称为待决中断,它会在刚调用 sleep()方法时,立即抛出 InterruptedException 异常
3 子线程中的异常不往父线程抛
4 线程一旦被中断,isInterrupted()方法便会返回 true, 但是当抛出异常或者使用iterrupted()返回中断状态,isInterrupted将被清空
5 使用 volatile 变量,必须同时满足下面两个条件:
a 对变量的写操作不依赖于当前值。
b 该变量没有包含在具有其他变量的不变式中。
6 Java中++, --不是原子操作,C++中是原子操作。 Java中读写double, long不是原子操作,可以添加volatile。
7 对象锁是用来控制实例方法之间的同步,类锁是用来控制静态方法(或静态变量互斥体)之间的同步。所以他们是两个不同的锁。不同实例的对象锁也是不同的。
8 使用wait(), notify(), notifyAll() 需要获取所在对象的对象级别锁(不包括类级锁),否则会抛出IllegalMonitorStateException异常
9 在使用线程的等待/通知机制时,要避免早期通知和通知遗漏。一般都要在 while 循环中调用 wait()方法,满足条件时,才让 while循环退出,这样一般也要配合使用一个 boolean 变量,满足 while 循环的条件时,进入 while 循环,执行 wait()方法,不满足 while 循环的条件时,跳出循环,执行后面的代码。经典用法
synchronized (shareMonitor) {
while(someCondition){
shareMonitor.wait();
}
}
10 I/O 和synchronized块伤的等待是不可中断的
11 检查中断。
当你在线程上调用interrupt()时,终端法师的唯一时刻是在任务要进入到课中断的阻塞操作或者已经在可中断的阻塞操作内部。一般需要两种方式来退出线程中的循环。一个是InterruptedException异常,一个是调用interrupt()来检查中断状态。经典惯用方法如下,参考了Thingking in Java
@Override
public void run() {
try {
//1 检查状态
while(!Thread.interrupted()){
NeedsCleanUp n1 = new NeedsCleanUp();
//每一个需要释放的资源后面都要紧跟着try finnally,确保资源能够释放
try {
Thread.sleep(1000);
NeedsCleanUp n2 = new NeedsCleanUp();
try {
} finally {
n2.cleanup();
}
} finally {
n1.cleanup();
}
}
System.out.println("通过while() 结束");
//捕获异常结束
} catch (InterruptedException e) {
System.out.println("2 通过InterruptedException 结束");
}
}
12 wait()在调用时候,要获得所在对象的对象锁,之后释放锁
sleep(), yield()在调用时候不需要获得锁,也不需要释放锁