多线程-java线程
java线程
6个线程状态
- New:尚未启动的线程的线程状态
- Runnable:可以运行线程的状态,等待CPU调度。
- Blocked:线程阻塞,等待监视器锁定的线程状态,处于synchronized同步代码块,或者方法当中被阻塞。
- Waiting:等待线程的线程状态,运行需要等待其他线程的通知:Object.wait(), Thread.join(), LockSupport.park()
- Timed Waiting:带超时的线程等待状态。比如下面带超时的例子:Thread.sleep(), Object.wait(t), Thread.join(t),LockSupport.parkNanos(),LockSupport.parkUntil()
- Terminal:终止,线程终止之后,再进行调用,会抛出IllegalThreadStateException异常。
线程间操作:
- 一般读,一般写
- volatile读,volatile写
- lock,unlock
- 进入进程的第一条和最后一条语句。
同步就是可见
可见就是不被缓存。
对于同步的规则定义:
- 对volatile变量v的写入,和所有其他线程后续,对v的读同步。
- 对于监视器m的解锁,和所有后续操作,对m的加锁同步。
- 加锁后解锁不应该被指令重排。
- 解锁对后面的加锁同步。
- 对于每个属性,写入默认值(0,false,null)与每个线程对齐的操作同步。
- 启动线程的操作,和线程中的第一个操作同步。
- T2的最后操作,和线程的最后一个状态同步。
修改state状态,读取state状态不能被缓存。
如果T1中断了T2,interrupt,
Happens-before:先行发生原则。
描述两个有冲突的动作之间的顺序,如果一个action happens before另一个action,那么第一个操作被第二个操作可见,JVM需要实现如下的happens-before规则。
- 某个线程中的每个动作,都happens-before该线程中该动作后面的动作。
- 某个管程上的unlock动作happens-before同一个管程上后续的lock操作。
- 对某个volatile字段的写操作happens-before每个后续对该volatile字段的读操作。
- 在某个线程对象上,调用start方法,happens-before被启动线程中的任意动作。
- 如果在t1当中成功执行了t2.join,则t2中的所有操作对t1可见。
- 如果某个动作a,happens-before动作b,并且b happens-before动作c,则有a happens-before c。
JMM对final的处理
final在这个对象的构造函数中设置对象的字段,当线程看到这个对象的时候,将始终看到这个对象的final字段的正确构造版本。比如f = new finalDemo(),x是f的final字段,f.x读取到的一定是最新的。
如果在构造函数当中,设置字段之后发生读取,则会看到这个final字段分配的值,否则将看到默认值。
比如public finalDemo(){x=1;y=x;},y会等于1;
读取这个共享对象的final成员变量之前,先要读取共享对象。
r=new ReferenceObj(); k=r.f;这两个操作不能重排序。
static final不能被修改。
System.in, System.out, System.err被staticfinal修饰却可以被修改。
遗留问题,必须允许通过set方法来改变。讲这些字段称为写保护,区别普通的final字段。
Word Tearing字节处理。
尽量不要对byte[]中的元素进行重新复制,更不要在多线程程序中这样做。
double和long的特殊处理。
读写volatile修饰的long,double是原子性的。
如果long和double是线程共享的,那么最好用volatile修饰。
JAVA内存模型:多线程下的java语言的执行规则。
JVM内存模型:java内存当中,每个区域的作用以及回收方式。
- 高速缓存
- 指令重排。
- volatile