在java中,解决同步问题,不少时候都会使用到synchronized和Lock,这二者都是在多线程并发时候常使用的锁机制。java
synchronized是java中的一个关键字,也就是说是java内置的一个特性。当一个线程访问一个被synchronized修饰的代码块,会自动获取对应的一个锁,并在执行该代码块时,其余线程想访问这个代码块,会一直处于等待状态,自有等该线程释放锁后,其余线程进行资源竞争,竞争获取到锁的线程才能访问该代码块。bash
线程释放synchronized修饰的代码块锁的方式有两种:多线程
采用synchronized关键字来实现同步,会致使若是存在多个线程想执行该代码块,而当前获取到锁的线程又没有释放锁,可想而知,其余线程只有一只等待,这将严重印象执行效率。Lock锁机制的出现就是为了解决该现象。Lock是一个java接口,经过这个接口能够实现同步,使用Lock时,用户必须手动进行锁的释放,不然容易出现死锁。 并发
ReentranLock是Lock的惟一实现类。下面简单介绍一下ReentranLock与synchronized的区别:ide
公平锁:当线程A获取访问该对象,获取到锁后,此时内部存在一个计数器num+1,其余线程想访问该对象,就会进行排队等待(等待队列最前一个线程处于待唤醒状态),直到线程A释放锁(num = 0),此时会唤醒处于待唤醒状态的线程进行获取锁的操做,一直循环。若是线程A再次尝试获取该对象锁是,会检查该对象锁释放已经被占用,若是被占用,会作一次是否为当前线程占用锁的判断,若是是内部计数器num+1,而且不须要进入等待队列,而是直接回去当前锁。测试
非公平锁:当线程A在释放锁后,等待对象的线程会进行资源竞争,竞争成功的线程将获取该锁,其余线程继续睡眠。ui
公平锁是严格的以FIFO的方式进行锁的竞争,可是非公平锁是无序的锁竞争,刚释放锁的线程很大程度上能比较快的获取到锁,队列中的线程只能等待,因此非公平锁可能会有“饥饿”的问题。可是重复的锁获取能减少线程之间的切换,而公平锁则是严格的线程切换,这样对操做系统的影响是比较大的,因此非公平锁的吞吐量是大于公平锁的,这也是为何JDK将非公平锁做为默认的实现。spa
下面是接口Lock的方法:操作系统
附上对接口Lock方法的测试,有什么问题欢迎各位留言评论。线程
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TestLock {
// ReentrantLock为Lock的惟一实现类
private Lock lock = new ReentrantLock();
/**
* 测试使用lock 的 lock()方法 :若是锁已经被其余线程获取,则等待
* @param thread
*/
public void testLock(Thread thread){
try {
// 1.获取锁
lock.lock();
System.out.println("线程 " + thread.getName() + " 获取了锁!");
}catch (Exception e){
e.printStackTrace();
}finally {
System.out.println("线程 " + thread.getName() + " 释放了锁!");
// 必须在 finally 中释放锁,防止死锁
lock.unlock();
}
}
/**
* 测试使用lock 的 lock()方法 :经过这个方法去获取锁时,若是线程正在等待获取锁,则这个线程可以响应中断,即中断线程的等待状态。
* @param thread
*/
public void testLockInterruptibly(Thread thread){
try {
// 1.获取锁
lock.lockInterruptibly();
System.out.println("线程 " + thread.getName() + " 获取了锁!");
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}finally {
System.out.println("线程 " + thread.getName() + " 释放了锁!");
// 必须在 finally 中释放锁,防止死锁
lock.unlock();
}
}
/**
* 测试使用lock 的 tryLock()方法 :若是获取成功,则返回true,若是获取失败(即锁已被其余线程获取),则返回false
* @param thread
*/
public void testTryLock(Thread thread){
if(lock.tryLock()){// 若是获取到了锁
try {
System.out.println("线程 " + thread.getName() + " 获取了锁!");
Thread.sleep(3000);
}catch (Exception e){
e.printStackTrace();
}finally {
System.out.println("线程 " + thread.getName() + " 释放了锁!");
// 必须在 finally 中释放锁,防止死锁
lock.unlock();
}
}else {
// 没有获取到锁
System.out.println("线程 " + thread.getName() + " 没有获取到锁!");
}
}
/**
* 测试使用lock 的 tryLock(long time, TimeUnit unit)方法 :和tryLock()方法是相似的,只不过区别在于这个方法在拿不到锁时会等待必定的时间,
* 在时间期限以内若是还拿不到锁,就返回false。若是若是一开始拿到锁或者在等待期间内拿到了锁,则返回true。
* @param thread
*/
public void testTryLock_time_unit(Thread thread){
try {
if(lock.tryLock(1000, TimeUnit.MILLISECONDS)){// 若是获取到了锁
try {
System.out.println("线程 " + thread.getName() + " 获取了锁!");
}catch (Exception e){
e.printStackTrace();
}finally {
System.out.println("线程 " + thread.getName() + " 释放了锁!");
// 必须在 finally 中释放锁,防止死锁
lock.unlock();
}
}else {
// 没有获取到锁
System.out.println("线程 " + thread.getName() + " 没有获取到锁!");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args){
TestLock testLock = new TestLock();
Thread a = new Thread("A") {
@Override
public void run() {
/*// 测试 lock()
testLock.testLock(Thread.currentThread());*/
/*// 测试 lockInterruptibly()
testLock.testLockInterruptibly(Thread.currentThread());*/
/*// 测试 tryLock()
testLock.testTryLock(Thread.currentThread());*/
/*// 测试 tryLock(long time, TimeUnit unit)
testLock.testTryLock_time_unit(Thread.currentThread());*/
testLock.testTryLock_time_unit(Thread.currentThread());
}
};
Thread b = new Thread("B") {
@Override
public void run() {
testLock.testTryLock(Thread.currentThread());
}
};
a.start();
b.start();
}
}
复制代码