由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题。Java语言提供了专门机制以解决这种冲突,有效避免了同一个数据对象被多个线程同时访问。在分布式开发中,锁是线程控制的重要途径。Java为此也提供了2种锁机制,synchronized和lock。
1.synchronized
示例1:
private void synMethod() {
doSomething();
//代码块加锁
synchronized (this) {
doSomething1();
}
doSomething2();
}
示例2:
//方法上加锁,可以锁住整个方法,保证数据安全性,但是相对代码块加锁,性能上有稍微影响
private synchronized void synMethod() {
doSomething1();
doSomething1();
doSomething2();
}
所以建议高并发时,同步调用应该去考量锁的性能损耗。能用无锁数据结构,就不要用锁;能锁区块,就不要锁整个方法体;能用对象锁,就不要用类锁。这里对象锁和类锁不做介绍,感兴趣的同学可以去查下资料(相信大家从名字上就可以猜测到它们的区别)
2.lock
一般使用ReentrantLock类做为锁,多个线程中必须要使用一个ReentrantLock类做为对象才能保证锁的生效。且在加锁和解锁处需要通过lock()和unlock()显示指出。所以一般会在finally块中写unlock()以防死锁。
示例:
ReentrantLocklock = new ReentrantLock();
// ...
lock.lock();
try {
doSomething();
doOthers();
} finally {
lock.unlock();
}
总结:synchronized是托管给JVM执行的,而lock是java写的控制锁的代码。在Java1.5中,synchronize是性能低效的。因为这是一个重量级操作,需要调用操作接口,导致有可能加锁消耗的系统时间比加锁以外的操作还多。相比之下使用Java提供的Lock对象,性能更高一些。但是到了Java1.6,发生了变化。synchronize在语义上很清晰,可以进行很多优化,有适应自旋,锁消除,锁粗化,轻量级锁,偏向锁等等。导致在Java1.6上synchronize的性能并不比Lock差。官方也表示,他们也更支持synchronize,在未来的版本中还有优化余地。所以在jdk新的版本中我们一般会使用synchronize更多一些。
网友评论