精华帖 (6) :: 良好帖 (5) :: 新手帖 (13) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2012-03-30
核桃博客 写道 说一说java的concurrent包4--可以代替synchronized关键字的ReentrantLock
http://www.hetaoblog.com/%E8%AF%B4%E4%B8%80%E8%AF%B4java%E7%9A%84concurrent%E5%8C%854-%E5%8F%AF%E4%BB%A5%E4%BB%A3%E6%9B%BFsynchronized%E5%85%B3%E9%94%AE%E5%AD%97%E7%9A%84reentrantlock/ 在jdk 1.4时代,线程间的同步主要依赖于synchronized关键字,本质上该关键字是一个对象锁,可以加在不同的instance上或者class上,从使用的角度则分别可以加在非静态方法,静态方法,以及直接synchronized(MyObject)这样的用法; concurrent包提供了一个可以替代synchronized关键字的ReentrantLock, 简单的说你可以new一个ReentrantLock, 然后通过lock.lock和lock.unlock来获取锁和释放锁;注意必须将unlock放在finally块里面, reentrantlock的好处 1. 是更好的性能, 2. 提供同一个lock对象上不同condition的信号通知 3. 还提供lockInterruptibly这样支持响应中断的加锁过程,意思是说你试图去加锁,但是当前锁被其他线程hold住,然后你这个线程可以被中断; 简单的一个例子: package com.hetaoblog.concurrent.test; import java.util.concurrent.CountDownLatch; import java.util.concurrent.locks.ReentrantLock; import org.junit.Test; public class ReentrantLockDemo { @Test public void demoLock() { final int loopcount = 10000; int threadcount = 10; final SafeSeqWithLock seq = new SafeSeqWithLock(); final CountDownLatch l = new CountDownLatch(threadcount); for(int i = 0; i < threadcount; ++i) { final int index = i; new Thread(new Runnable() { @Override public void run() { for(int j = 0; j < loopcount; ++j) { seq.inc(); } System.out.println("finished : " + index); l.countDown(); } }).start(); } try { l.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("both have finished...."); System.out.println("SafeSeqWithLock:" + seq.get()); } } class SafeSeqWithLock{ private long count = 0; private ReentrantLock lock = new ReentrantLock(); public void inc() { lock.lock(); try{ count++; } finally{ lock.unlock(); } } public long get() { return count; } } 同样以前面的类似Sequence的类举例,通过对inc操作加锁,保证了线程安全; 当然,这里get()我没有加锁,对于这样直接读取返回原子类型的函数,我认为不加锁是没问题的,相当于返回最近成功操作的值; 运行结果类似这样, finished : 7 finished : 2 finished : 6 finished : 1 finished : 5 finished : 3 finished : 0 finished : 9 finished : 8 finished : 4 both have finished.... SafeSeqWithLock:100000 这一段是肯定有问题的,返回get没有sync那必然会出错 很明显就看出来你只有一个线程在get...你多加几个线程来执行 final SafeSeqWithLock seq = new SafeSeqWithLock(); seq.inc(); 就会发现问题了,但是用原子操作的话,get也就不需要同步了..试试看. ^_^ |
|
返回顶楼 | |
发表时间:2012-03-30
最后修改:2012-03-30
强烈建议说下AbstractQueuedSynchronizer的原理以及线程安全问题(主要是可见性问题)
我有浓烈兴趣 |
|
返回顶楼 | |
发表时间:2012-03-30
天籁の圁 写道 核桃博客 写道 说一说java的concurrent包4--可以代替synchronized关键字的ReentrantLock
http://www.hetaoblog.com/%E8%AF%B4%E4%B8%80%E8%AF%B4java%E7%9A%84concurrent%E5%8C%854-%E5%8F%AF%E4%BB%A5%E4%BB%A3%E6%9B%BFsynchronized%E5%85%B3%E9%94%AE%E5%AD%97%E7%9A%84reentrantlock/ 在jdk 1.4时代,线程间的同步主要依赖于synchronized关键字,本质上该关键字是一个对象锁,可以加在不同的instance上或者class上,从使用的角度则分别可以加在非静态方法,静态方法,以及直接synchronized(MyObject)这样的用法; concurrent包提供了一个可以替代synchronized关键字的ReentrantLock, 简单的说你可以new一个ReentrantLock, 然后通过lock.lock和lock.unlock来获取锁和释放锁;注意必须将unlock放在finally块里面, reentrantlock的好处 1. 是更好的性能, 2. 提供同一个lock对象上不同condition的信号通知 3. 还提供lockInterruptibly这样支持响应中断的加锁过程,意思是说你试图去加锁,但是当前锁被其他线程hold住,然后你这个线程可以被中断; 简单的一个例子: package com.hetaoblog.concurrent.test; import java.util.concurrent.CountDownLatch; import java.util.concurrent.locks.ReentrantLock; import org.junit.Test; public class ReentrantLockDemo { @Test public void demoLock() { final int loopcount = 10000; int threadcount = 10; final SafeSeqWithLock seq = new SafeSeqWithLock(); final CountDownLatch l = new CountDownLatch(threadcount); for(int i = 0; i < threadcount; ++i) { final int index = i; new Thread(new Runnable() { @Override public void run() { for(int j = 0; j < loopcount; ++j) { seq.inc(); } System.out.println("finished : " + index); l.countDown(); } }).start(); } try { l.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("both have finished...."); System.out.println("SafeSeqWithLock:" + seq.get()); } } class SafeSeqWithLock{ private long count = 0; private ReentrantLock lock = new ReentrantLock(); public void inc() { lock.lock(); try{ count++; } finally{ lock.unlock(); } } public long get() { return count; } } 同样以前面的类似Sequence的类举例,通过对inc操作加锁,保证了线程安全; 当然,这里get()我没有加锁,对于这样直接读取返回原子类型的函数,我认为不加锁是没问题的,相当于返回最近成功操作的值; 运行结果类似这样, finished : 7 finished : 2 finished : 6 finished : 1 finished : 5 finished : 3 finished : 0 finished : 9 finished : 8 finished : 4 both have finished.... SafeSeqWithLock:100000 这一段是肯定有问题的,返回get没有sync那必然会出错 很明显就看出来你只有一个线程在get...你多加几个线程来执行 final SafeSeqWithLock seq = new SafeSeqWithLock(); seq.inc(); 就会发现问题了,但是用原子操作的话,get也就不需要同步了..试试看. ^_^ 想了下,可能的确不对,加上volatile应该就可以 |
|
返回顶楼 | |
发表时间:2012-03-30
freish 写道 强烈建议说下AbstractQueuedSynchronizer的原理以及线程安全问题(主要是可见性问题)
我有浓烈兴趣 好的,下次会慢慢加上的,多谢关注:) |
|
返回顶楼 | |