Java多线程之synchronized和Lock

1. synchronized与Lock的区别

synchronized和Lock都是Java实现多线程同步的方法,但是它们有所不同,具体就是:
(1)用法不同。synchronized是将需要同步的对象,加上synchronized控制,有synchronized块,synchronized方法,它最终是交给JVM来执行同步的。而Lock需要显示的指定起始位置和终止位置,Lock的同步是通过自己的代码实现的,提供了锁投票、定时锁、等候和中断锁等更精确的线程语义。
(2)性能不同。在资源竞争不激烈的情况下synchronized的性能要优于Lock,但是随着激烈竞争的增加,synchronized的性能会下降的很快。
具体见 http://blog.csdn.net/fw0124/article/details/6672522(Java中的ReentrantLock和synchronized两种锁定机制的对比)。
(3)锁机制不同。synchronized锁的获取释放都存在于块结构中,锁的释放顺序与获取顺序相反,不需要开发人员控制,是自动解锁。但是Lock是在finally块中释放 ,需要手动解锁。Lock还提供了很多其他的功能,比如tryLock()、lockInterruptibly()等方法。

2. Lock以及ReentrantLock的详细介绍

(1)Lock是一个接口,ReebtrantLick是实现这个接口的一个类。
Lock的实现提供了比synchronized更多的锁处理的方法,就是可以通过Lock控制线程执行的顺序。
通常习惯的用法是:
Lock l = ...;
 l.lock();
 try {
   // access the resource protected by this lock
 } finally {
   l.unlock();
 }

(2)Lock接口的6个方法:
void lock()
Acquires the lock.
void lockInterruptibly()
Acquires the lock unless the current thread is  interrupted.
Condition newCondition()
Returns a new  Condition instance that is bound to this  Lock instance.
boolean tryLock()
Acquires the lock only if it is free at the time of invocation.
boolean tryLock(long time, TimeUnit unit)
Acquires the lock if it is free within the given waiting time and the current thread has not been  interrupted.
void unlock()
Releases the lock.

(3)ReentrantLock
public class ReentrantLock
extends Object
implements Lock, Serializable
通过ReentrantLock实现的接口可以看出,它主要用来作为实体类,服务于多线程同步问题,另外,它还实现了Serializable接口,说明它具有了序列化功能。所谓的Serializable,就是java提供的通用数据保存和读取的接口。至于从什么地方读出来和保存到哪里去都被隐藏在函数参数的背后了。这样子,任何类型只要实现了Serializable接口,就可以被保存到文件中,或者作为数据流通过网络发送到别的地方。也可以用管道来传输到系统的其他程序中。这样子极大的简化了类的设计。

3. Lock的用法实例

(1) lock.lock()
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TestLock {

	public static void main(String[] args) {
		Thread t1 = new Thread(new RunIt());
		Thread t2 = new Thread(new RunIt());
		
		t2.start();
		t2.interrupt();
		t1.start();
	}
}

class RunIt implements Runnable {

	private static Lock lock = new ReentrantLock();

	@Override
	public void run() {
		try {
			runJob();
		} catch (InterruptedException e) {
			System.out.println(Thread.currentThread().getName()
					+ " Interrrupted from runJob.");
		}
	}

	private void runJob() throws InterruptedException {
		//lock.lockInterruptibly();
		lock.lock();
		System.out.println(Thread.currentThread().getName() + " 到此一游....");
		try {
			System.out.println(Thread.currentThread().getName() + " running");
			TimeUnit.SECONDS.sleep(3);
			System.out.println(Thread.currentThread().getName() + " finished");

		} catch (InterruptedException e) {
			System.out.println(Thread.currentThread().getName()
					+ " interrupted");
		} finally {
			lock.unlock();
		}
	}
}
lock.lock()会一直等待锁,所以它的运行结果是:
Thread-0 到此一游....
Thread-0 running
Thread-0 finished
Thread-1 到此一游....
Thread-1 running
Thread-1 interrupted

(2)lock.lockInterruptibly()
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class TestLock {

	public static void main(String[] args) {
		Thread t1 = new Thread(new RunIt());
		Thread t2 = new Thread(new RunIt());
		t1.start();
		t2.start();
		t2.interrupt();

	}
}

class RunIt implements Runnable {

	private static Lock lock = new ReentrantLock();

	@Override
	public void run() {
		try {
			runJob();
		} catch (InterruptedException e) {
			System.out.println(Thread.currentThread().getName()
					+ " Interrrupted from runJob.");
		}
	}

	private void runJob() throws InterruptedException {
		lock.lockInterruptibly();
		//lock.lock();
		System.out.println(Thread.currentThread().getName() + " 到此一游....");
		try {
			System.out.println(Thread.currentThread().getName() + " running");
			TimeUnit.SECONDS.sleep(3);
			System.out.println(Thread.currentThread().getName() + " finished");

		} catch (InterruptedException e) {
			System.out.println(Thread.currentThread().getName()
					+ " interrupted");
		} finally {
			lock.unlock();
		}
	}
}
lock.lockInterruptibly()方法比较特殊,当通过这个方法去获取锁时,如果线程正在等待获取锁,则这个线程能够响应中断,即中断线程的等待状态。也就使说,当两个线程同时通过lock.lockInterruptibly()想获取某个锁时,假若此时线程A获取到了锁,而线程B只有在等待,那么对线程B调用threadB.interrupt()方法能够中断线程B的等待过程。
它的运行结果是:
Thread-0 到此一游....
Thread-1 Interrrupted from runJob.
Thread-0 running
Thread-0 finished

对比一下两段代码的运行结果可以看出,由于thread -1执行了interrupt(),在通过lockInterruptibly()获取锁的过程中,它的等待过程被中断了,此时会抛出异常,所以执行的是Interrupted from rubJob,而通过lock()获取锁的等待不会因为执行interrupt()而中断,所以thread -1也能获得锁,但是在sleep()的时候,响应了interrupt,所以抛出了interrupted异常。

欢迎转载,但请注明出处:http://blog.csdn.net/amazing_happens/article/details/50818264

你可能感兴趣的:(Java)