Threads and Locks
转载自:https://javadoop.com/post/Threads-And-Locks-md
主要是对原文加上自己的理解与标注
-
Thread.sleep 和 Thread.yield 都不具有同步的语义。在 Thread.sleep 和 Thread.yield 方法调用之前,不要求虚拟机将寄存器中的缓存刷出到共享内存中,同时也不要求虚拟机在这两个方法调用之后,重新从共享内存中读取数据到缓存。
-
调用thread的interrupt方法,会导致它从对象锁的等待集合中剔除,如果interrupt和notify同时调用,如果notify先执行,则线程正常返回同时中断状态为true,如果interrupt先执行则线程获取到监视器锁后,继续执行会报InterruptedException异常
-
对象的默认初始值 happens-before 于程序中对它的其他操作
也就是说不管我们要对这个对象干什么,这个对象即使没有创建完成,它的各个属性也一定有初始零值。 -
如果 A 线程中调用了 B.join(),那么 B 线程中的操作先于 A 线程 join() 返回之后的任何语句。因为 join() 本身就是让其他线程先执行完的意思。
-
对象只有在构造方法结束了才被认为完全初始化了。如果一个对象完全初始化以后,一个线程持有该对象的引用,那么这个线程一定可以看到正确初始化的 final 属性的值。在对象的构造方法中设置 final 属性;同时在对象初始化完成前,不要将此对象的引用写入到其他线程可以访问到的地方(也就是在构造函数中,不要把this对象暴露出去)。如果这个条件满足,当其他线程看到这个对象的时候,那个线程始终可以看到正确初始化后的对象的 final 属性(这个也解释了双重检验锁中变量如果为final ,不存在变量没有初始化完成就暴露出去了,final 属性的写操作不会和此引用的赋值操作发生重排序)。
-
线程会因为以下原因从等待集合中剔除:
以下三种输出对第二点进行验证:
第一种输出
package com.tuniu.tmc.apaas.order.controller;
public class WaitNotify {
volatile int a = 0;
public static void main(String[] args) {
Object object = new Object();
WaitNotify waitNotify = new WaitNotify();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (object) {
System.out.println("线程1 获取到监视器锁");
try {
object.wait();
System.out.println("线程1 正常恢复啦。" + Thread.interrupted());
} catch (InterruptedException e) {
System.out.println("线程1 wait方法抛出了InterruptedException异常");
}
}
}
}, "线程1");
thread1.start();
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (object) {
System.out.println("线程2 获取到监视器锁");
try {
object.wait();
System.out.println("线程2 正常恢复啦。");
} catch (InterruptedException e) {
System.out.println("线程2 wait方法抛出了InterruptedException异常");
}
}
}
}, "线程2");
// thread2.start();
// 这里让 thread1 和 thread2 先起来,然后再起后面的 thread3
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
new Thread(new Runnable() {
@Override
public void run() {
synchronized (object) {
System.out.println("线程3 拿到了监视器锁。");
System.out.println("线程3 设置线程1中断");
thread1.interrupt(); // 1
waitNotify.a = 1; // 这行是为了禁止上下的两行中断和notify代码重排序
System.out.println("线程3,休息一会");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
System.out.println("线程3 休息够了");
System.out.println("线程3 调用notify");
object.notify(); //2
}
}
}, "线程3").start();
}
}
输出结果:
线程1 获取到监视器锁
线程3 拿到了监视器锁。
线程3 设置线程1中断
线程3,休息一会
线程3 休息够了
线程3 调用notify
线程1 wait方法抛出了InterruptedException异常
第二种输出:
package com.tuniu.tmc.apaas.order.controller;
public class WaitNotify {
volatile int a = 0;
public static void main(String[] args) {
Object object = new Object();
WaitNotify waitNotify = new WaitNotify();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (object) {
System.out.println("线程1 获取到监视器锁");
try {
object.wait();
System.out.println("线程1 正常恢复啦。" + Thread.interrupted());
} catch (InterruptedException e) {
System.out.println("线程1 wait方法抛出了InterruptedException异常");
}
}
}
}, "线程1");
thread1.start();
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (object) {
System.out.println("线程2 获取到监视器锁");
try {
object.wait();
System.out.println("线程2 正常恢复啦。");
} catch (InterruptedException e) {
System.out.println("线程2 wait方法抛出了InterruptedException异常");
}
}
}
}, "线程2");
// thread2.start();
// 这里让 thread1 和 thread2 先起来,然后再起后面的 thread3
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
new Thread(new Runnable() {
@Override
public void run() {
synchronized (object) {
System.out.println("线程3 拿到了监视器锁。");
System.out.println("线程3 设置线程1中断");
thread1.interrupt(); // 1
waitNotify.a = 1; // 这行是为了禁止上下的两行中断和notify代码重排序
System.out.println("线程3 调用notify");
object.notify(); //2
System.out.println("线程3 调用完notify后,休息一会");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
System.out.println("线程3 休息够了,结束同步代码块");
}
}
}, "线程3").start();
}
}
输出结果:
线程1 获取到监视器锁
线程3 拿到了监视器锁。
线程3 设置线程1中断
线程3 调用notify
线程3 调用完notify后,休息一会
线程3 休息够了,结束同步代码块
线程1 wait方法抛出了InterruptedException异常
或者
线程1 获取到监视器锁
线程3 拿到了监视器锁。
线程3 设置线程1中断
线程3 调用notify
线程3 调用完notify后,休息一会
线程3 休息够了,结束同步代码块
线程1 正常恢复啦。true
第三种输出:如果一个线程同时被中断和通知唤醒,同时这个线程通过抛出 InterruptedException 异常从 wait 中返回,那么等待集合中的某个其他线程一定会被通知。 也就是说等待集合中其它线程被选中,继续执行
/**
* Created by hongjie on 2017/7/7.
*
*/
public class WaitNotify {
volatile int a = 0;
public static void main(String[] args) {
Object object = new Object();
WaitNotify waitNotify = new WaitNotify();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (object) {
System.out.println("线程1 获取到监视器锁");
try {
object.wait();
System.out.println("线程1 正常恢复啦。");
} catch (InterruptedException e) {
System.out.println("线程1 wait方法抛出了InterruptedException异常");
}
}
}
}, "线程1");
thread1.start();
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
synchronized (object) {
System.out.println("线程2 获取到监视器锁");
try {
object.wait();
System.out.println("线程2 正常恢复啦。");
} catch (InterruptedException e) {
System.out.println("线程2 wait方法抛出了InterruptedException异常");
}
}
}
}, "线程2");
thread2.start();
// 这里让 thread1 和 thread2 先起来,然后再起后面的 thread3
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
new Thread(new Runnable() {
@Override
public void run() {
synchronized (object) {
System.out.println("线程3 拿到了监视器锁。");
System.out.println("线程3 设置线程1中断");
thread1.interrupt(); // 1
waitNotify.a = 1; // 这行是为了禁止上下的两行中断和notify代码重排序
System.out.println("线程3 调用notify");
object.notify(); //2
System.out.println("线程3 调用完notify后,休息一会");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
}
System.out.println("线程3 休息够了,结束同步代码块");
}
}
}, "线程3").start();
}
}
// 最常见的output:
线程1 获取到监视器锁
线程2 获取到监视器锁
线程3 拿到了监视器锁。
线程3 设置线程1中断
线程3 调用notify
线程3 调用完notify后,休息一会
线程3 休息够了,结束同步代码块
线程2 正常恢复啦。
线程1 wait方法抛出了InterruptedException异常
上一篇: ES6变量的两种命名方式
下一篇: ES6返回JSX的两种方式
推荐阅读
-
Yum中报错:“pycurl.so: undefined symbol: CRYPTO_num_locks”的问题排查
-
PHP安装threads多线程扩展基础教程
-
mysql 数据库 Database page corruption 时的恢复参数 innodb_force_recovery、innodb_purge_threads
-
Java Concurrency: Thread&Locks
-
Threads and Executors
-
wxPython and Threads
-
Threads and Executors
-
2017 6.824学习笔记 Lecture 2: RPC and threads
-
Processes and Threads
-
Lecture 2: Infrastructure: RPC and threads