线程开始运行,拥有自己的栈空间。线程之间的通信给线程带来了巨大的价值
Volatile与Synchronized关键字
问题引出:
使用volatile修饰int型变量i,多个线程同时进行i++操作,这样可以实现线程安全吗?
- volatile修饰的变量具有可见性。可见性也就是说一旦某个线程修改了该被volatile修饰的变量,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,可以立即获取修改之后的值。在Java中为了加快程序的运行效率,对一些变量的操作通常是在该线程的寄存器或是CPU缓存上进行的,之后才会同步到主存中,而加了volatile修饰符的变量则是直接读写主存。
volatile禁止指令重排 ,指令重排是指处理器为了提高程序运行效率,可能会对输入代码进行优化,它不保证各个语句的执行顺序同代码中的顺序一致,但是它会保证程序最终执行结果和代码顺序执行的结果是一致的。指令重排序不会影响单个线程的执行,但是会影响到线程并发执行的正确性。程序执行到volatile修饰变量的读操作或者写操作时,在其前面的操作肯定已经完成,且结果已经对后面的操作可见,在其后面的操作肯定还没有进行。
synchronized可作用于一段代码或方法,既可以保证可见性,又能够保证原子性。可见性体现在:通过synchronized或者Lock能保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存中。
原子性表现在:要么不执行,要么执行到底。
总结
- 从而我们可以看出volatile虽然具有可见性但是并不能保证原子性。
- 性能方面,synchronized关键字是防止多个线程同时执行一段代码,就会影响程序执行效率,而volatile关键字在某些情况下性能要优于synchronized。
- 但是要注意volatile关键字是无法替代synchronized关键字的,因为volatile关键字无法保证操作的原子性。
等待通知机制
范式,该范式分为两部分,分别是等待方,通知方。
等待方:
1. 获取对象的锁
2. 如果条件不满足,那么调用对象的wait()方法,被通知后仍要检查条件
3. 条件满足则执行对应的逻辑, 代码如下
boolean conditioned=true;
synchronized (object){
while(conditioned){
object.wait();
}
//... 对应的业务逻辑
}
通知方:
1. 获得对象的锁
2. 改变条件
3. 通知所有等待在对象上的线程
synchronized(object){
//改变条件
object.notifyAll();
}
Thread.join()
如果一个线程A执行了thread.join(),含义是:当前线程A等待thread线程终止后才能thread.join()返回。
函数
//Waits for this thread to die.
void join()
//Waits at most millis milliseconds for this thread to die.
void join(long millis)
//Waits at most millis milliseconds plus nanos nanoseconds for this thread to die.
void join(long millis, int nanos)
参考文档
https://blog.csdn.net/seu_calvin/article/details/52370068
https://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html