且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

java.util.concurrent包(1)——lock和synchronized对比

更新时间:2022-01-17 11:16:45

一、对synchronized的改进
JDK5后引入了线程并发库java.util.concurrent。JSR 166小组花了这么多时间来开发java.util.concurrent.lock框架呢?答案很简单——synchronized同步是不错,但它并不完美,有一些功能性的限制:无法中断一个正在等候获得锁的线程,也无法通过投票得到锁,如果不想等下去也就没法得到锁。同步还要求锁的释放只能在与获得锁所在的堆栈帧相同的堆栈帧中进行,多数情况下这没问题,而且与异常处理交互得很好,但确实存在一些非块结构的锁定更合适的情况。


二、ReentrantLock类

java.util.concurrent.lock中的Lock框架是锁定的一个抽象,它允许把锁定的实现作为Java类,而不是作为语言的特性来实现。这就为Lock的多种实现留下了空间,各种实现可能有不同的调度算法、性能特性或者锁定语义。ReentrantLock类实现了Lock,它拥有与synchronized相同的并发性和内存语义,但是添加了类似锁投票、定时锁等候和可中断锁等候的一些特性。此外它还提供了在激烈争用情况下更佳的性能,也就是说当许多线程都想访问共享资源时,JVM可以花更少的时候来调度线程,把更多时间用在执行线程上。

Reentrant锁意味着什么呢?简单来说它有一个与锁相关的获取计数器,如果拥有锁的某个线程再次得到锁,那么获取计数器就加1,然后锁需要被释放两次才能获得真正释放。这模仿了synchronized的语义:如果线程进入由线程已经拥有的监控器保护的synchronized块,就允许线程继续进行,当线程退出第二个或者后续synchronized 块时不释放锁,只有线程退出它进入的监控器保护的第一个synchronized块时才释放锁。

lock必须在finally块中释放。否则如果受保护的代码将抛出异常,锁就有可能永远得不到释放,忘记在finally块中释放锁非常麻烦。而使用synchronized同步,JVM将确保锁会获得自动释放。


三、代码对比
synchronized同步

public class SynchronizeOutput
{
public synchronizedvoid output(String name)
{
for (int i = 0; i < name.length(); i++)
{
System.out.print(name.charAt(i));
}
System.out.println();
}
}


public class SynchronizeTest
{
public static void main(String[] args)
{
final SynchronizeOutput synOutput = new SynchronizeOutput();


for (int i = 0; i < 100; i++)
{
new Thread(new Runnable() {
public void run()
{
synOutput.output("I am xy");
}
}).start();
}
}
}

Lock
public class LockOutput
{
Lock lock = new ReentrantLock();

public void output(String name)
{
lock.lock();
try
{
for (int i = 0; i < name.length(); i++)
{
System.out.print(name.charAt(i));
}
System.out.println();
}
finally
{
lock.unlock();
}
}
}

public class LockTest
{
public static void main(String[] args)
{
final LockOutput lockoutput = new LockOutput();
for (int i = 0; i < 100; i++)
{
new Thread(new Runnable() {
public void run()
{
lockoutput.output("I am xy");
}
}).start();
}
}

}

原帖地址:http://blog.csdn.net/fw0124/article/details/6672522