找工作哪个网站好智联招聘,做网站引流,微信拓客的最新方法,杭州软装公司排名前十强Synchronized 基本使用
1. 修饰实例方法
public class SynchronizedMethods{private int sum 0;public synchronized void calculate(){sum sum 1;}
}
这种情况下的锁对象是当前实例对象#xff0c;因此只有同一个实例对象调用此方法才会产生互斥效果#xff1b;不同的…Synchronized 基本使用
1. 修饰实例方法
public class SynchronizedMethods{private int sum 0;public synchronized void calculate(){sum sum 1;}
}
这种情况下的锁对象是当前实例对象因此只有同一个实例对象调用此方法才会产生互斥效果不同的实例对象之间不会有互斥效果。 比如如下代码 上述代码是在不同线程中用不同的对象调用 printLog() 方法彼此之间不会有排斥运行结果如下可以看出两个线程是交互执行的。 将上述代码做如下修改 两个线程调用同一个对象的 printLog() 方法 执行效果如下 只有某一个线程中的代码执行完后才会调用另外一个线程中的代码。此时两个线程之间是互斥的。 2. 修饰静态方法
如果 synchronized 修饰的是静态方法则锁对象是当前类的 Class 对象。即使在不同线程中调用不同实例对象也会有互斥效果。修改代码如下 执行结果如下可以看出两个线程还是依次执行的。 3. 修饰代码块
如果 synchronized 修饰的是代码块则锁对象是括号()里的对象。如下代码可以看出任何 Object 对象都可以看着锁对象 执行结果如下可以看出两个线程还是依次执行的。 实现细节
synchronized 既可以作用于方法也可以作用于代码块。但在实现上是有区别的比如如下代码使用 synchronized 作用于代码块 使用 javap -c Foo 查看上述代码的字节码如下 可以看出编译成的字节码包含 monitorenter 和 monitorexit 俩个字节码指令。
注意有两个 monitorexit。虚拟机需要保证当异常出现时也能释放锁因此两个 monitorexit 一个是代码正常执行结束后释放锁一个是代码执行异常时释放锁。
synchronized 修饰方法如下所示。被 synchronized 修饰方法被编译成字节码后在方法的 flags 属性中会被标记为 ACC_SYNCHRONIZED。当虚拟机访问一个被标记为ACC_SYNCHRONIZED的方法时会自动在方法开始和结束时添加 monitorenter 和 monitorexit 指令。 monitorenter 和 monitorexit 可以理解为一把具体的锁这个锁中保存着两个比较重要的属性计数器和指针。
计数器代表当前线程一共访问了几次这把锁
指针指向持有这把锁的线程。 ReentrantLock 的基本使用
ReentrantLock 的使用同 Synchronized 优点不同它的加锁和解锁需要手动完成。 如上代码所示ReentrantLock.lock() 和 ReentrantLock.unlock() 都需要手动完成。运行效果如下。ReentrantLock 也能实现于 Synchronized 相同的效果。
注意将 unlock() 操作放在 finally 代码块中是因为 ReentrantLock 并不会自动释放锁当异常发生时确保释放锁操作一定会被执行finally 里的代码在异常发生时也能执行。而 Synchronized 在异常发生时会自动释放锁。 公平锁实现
ReentrantLock 有一个带参数的构造器如下。 默认情况下 Synchronized 和 ReentrantLock 都是非公平锁但是 ReentrantLock 可以通过传入一个 true 来创建一个公平锁。
公平锁通过同步队列来实现多个线程按照申请锁的先后顺序获取锁。
使用实例如下 读写锁(ReentrantReadWriteLock)
在常见的开发中经常会定义一个线程间共享的用作缓存的数据结构。比如一个较大的 Map缓存中保存了全部的城市 Id 和 name 对应关系。这个大 Map 绝大部分时间提供读服务而写操作占用的时间很少通常是在服务器启动时初始化然后可以每隔一段时间再刷新缓存的数据。但是写操作开始到结束之间不能再有其它读操作进行并且写操作完成之后的更新数据需要对后续的读操作可见。
使用 concurrent 包中的读写锁ReentrantReadWriteLock实现上述功能只需要在读操作时获取读锁写操作时获取写锁即可。当写锁被获取到时后续的读写锁都会被阻塞写锁缩释放后所有操作继续执行。
读写锁的使用
1. 创建读写锁
ReentrantReadWriteLock rwLock new ReentrantReadWriteLock();
2. 通过读写锁对象分别获取读锁ReadLock和写锁Write Lock
ReentrantReadWriteLock.ReadLock readLock rwLock.readLock();
ReentrantReadWriteLock.ReadLock writeLock rwLock.writeLock();
3. 使用读锁同步缓存读操作使用写锁同步缓存写操作
// 读操作
readLock.lock();
try{// 从缓存中读取数据
} finally{readLock.unlock();
}// 写操作
writeLock.lock();
try{// 想缓存中写入数据
} finally{writeLock.lock();
}
具体实现 如上代码图中的 number 是线程中共享的数据用来模拟缓存数据图中1处分别创建2个 Reader 线程并从缓存中读取数据1个 Writer 将数据写入缓存中图中2处使用读锁ReadLock将读取数据的操作枷锁图中3处使用写锁WriteLock将写入数据到缓存中的操作加锁。 总结
● Java中两个实现同步的方式synchronized和ReentrantLock
● synchronized使用更简单加锁和释放锁都是由虚拟机自动完成
● ReentrantLock需要开发者手动去完成很Reentrantl ock的使用场景更多公平锁和读写锁都可以在复杂场景中发挥重要作用。