Volatile
并发编程中volatile和synchronize这两个关键字并不少见,可以理解为volatile就是轻量级synchronized,java多线程支持多个线程同时访问一个成员变量或对象,所以两个关键字都保证了共享变量的可见性,可见性就是当一个线程修改一个共享变量,另一个线程读取到这个共享变量被操作之后的值
随着jdk版本的迭代,synchronized关键字也被优化的很好,并没有所说的那么重
Volatile的实现原理
Java中允许多线程访问共享资源,确保线程安全和一致性,线程通过锁对象来单独获取资源
volatile在某些情况下比锁方便,如果一个变量被声明volatile,那么所有线程看到这个变量的值都是一致的
Volatile关键字的作用
volatile关键字的作用时禁止指令重排序,强制从公共堆栈中取得变量值,而不是从线程私有的数据栈取得变量的值
Synchronized
同步代码块,同步方法在我们的项目中很常见,作用就是用来保证多线程操作共享资源的一致性和原子性
确保共享资源在同一时刻只有一个线程可以访问,其他线程处于阻塞阶段,只有该线程执行完毕或出现异常,才会释放锁对象
其他线程才可以进行下一轮竞争CPU执行权(时间片)
Synchronized的实现原理
synchronized被人一直诟病为重量级锁,相比之下确实没有Lock那么灵活,方便,具体用法可以参考我以上文章Java 多线程之线程安全
!!!注意!!!
- 使用lock时在finally中必须释放锁,不然容易出现死锁,而使用synchronized时,不必担心,获取锁线程会在执行完同步代码后释放锁,或者JVM会在执行线程异常时释放锁对象
- 使用lock时线程不会一直等待,而使用synchronized时候,线程A获取对象锁以后,其他线程进入阻塞阶段并一直等待
- synchronized是隐式锁,在需要同步的资源加入此控制,而Lock锁是显示锁,需要在同步的资源前后加入获取锁和释放锁操作
Synchronized如何实现同步
同步代码块,对象可以为任意类型
也是在括号中写入this,代表当前锁对象就是当前类对象
public class RunnableImpl implements Runnable {
// 定义一个多个线程共享票源
private int ticket = 30;
// 创建锁对象
Object obj = new Object();
/**
* 卖票
*/
@Override
public void run() {
while (true) {
// 创建同步代码块
synchronized (obj) {
// 先判断票是否存在
if (ticket > 0) {
// 存在
System.out.println(Thread.currentThread().getName() + "--->正在卖票" + ticket + "张票");
ticket--;
}
}
}
}
}
同步方法,方法之上添加synchronized关键字
锁对象即是当前类的实例
public class RunnableImpl implements Runnable {
// 定义一个多个线程共享票源
private int ticket = 100;
/**
* 卖票
*/
@Override
public void run() {
while (true) {
updateTicket();
}
}
// 同步方法
public synchronized void updateTicket() {
// 先判断票是否存在
if (ticket > 0) {
// 存在
System.out.println(Thread.currentThread().getName() + "--->正在卖票" + ticket + "张票");
ticket--;
}
}
}
Volatile和Synchronized的区别
- volatile 不会发生线程阻塞,synchronized会发生线程阻塞
- volatile 只能修饰变量,synchronized可以修饰同步代码块和方法
- volatile 不能保证原子性(不能保证线程安全) ,synchronized可以保证原子性
- volatile 解决的是共享资源在多线程之间的可见性,synchronized 解决的是多线程之间访问共享资源的同步性