两者区别
- synchronized是关键字,在发生异常的时候会自动占用释放线程占用的锁,不会发生死锁现象。
- lock在发生异常时,如果没有主动通过unlock去释放锁,则很可能造成死锁现象。因此使用lock是需要在finally块释放对象锁。
- lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断。
- 通过lock可以知道有没有成功获得锁,而synchronized不能。
- lock可以提高多个线程进行读操作的效率。
synchronized 是可以重入锁
原理是:当线程在获得锁之后,每一个锁会关联一个线程对象和计数器,当一个线程请求成功后,会记录下持有锁的线程,并且计数器+1,其他线程来获得锁时,需要等待。当前线程再来获得锁时,计数器会递增,线程退出同步代码块时,计数器会递减,计数器为0,则释放锁
/**
* synchronized 是可重入锁
*/
public class BMW extends Car {
public synchronized void doSomething () throws Exception{
System.out.println ("BWM:doSomething:" + Thread.currentThread ().getName ());
carRun ();
}
public synchronized void carRun () throws Exception{
super.test ();
System.out.println ("BWM:carRun:" + Thread.currentThread ().getName ());
}
public static void main ( String[] args ) throws Exception{
BMW bmw = new BMW ();
bmw.doSomething ();
}
}
class Car {
public synchronized void test() throws Exception{
Thread.sleep (5000);
System.out.println ("car.test: "+Thread.currentThread ().getName ());
}
}
这里的对象锁只有一个,就是 BMW 对象的锁,当执行 BMW .doSomething 时,该线程获得 BMW 对象的锁,在 doSomething 方法内执行 carRun 时再次请求BMW 对象的锁,因为synchronized 是重入锁,所以可以得到该锁,继续在 carRun 里执行父类的 test方法时第三次请求 BMW 对象的锁,同样可得到。
lock
lock接口提供4种锁的方法,而ReentrantLock 是lock接口的唯一实现类。
- lock() :当前线程获得锁,其他线程只能等待,直到当前线程主动释放锁。
- lockInterruptibly() : 获得可中断锁,线程A通过此方法获得锁时,线程B再来获得锁时,A已经获得锁,B只能等待,此时B可以调用interrupt ()来终止线程.
- tryLock : 线程尝试去获得锁,如果获得到锁返回true,否则返回false。带时间参数的是如果没有获得错,等待多长时间再去尝试。
1、lock()
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.locks.ReentrantLock;
public class TestReenTrantLock {
private static Logger logger = LoggerFactory.getLogger (TestReenTrantLock.class);
public static void test () throws InterruptedException {
logger.info ("{}: 执行了",Thread.currentThread ());
Thread.sleep (5000);
logger.info ("{}: 执行了完成",Thread.currentThread ());
}
public static void main ( String[] args ) {
ReentrantLock r = new ReentrantLock ();
new Thread (){
@Override
public void run (){
logger.info ("{}: 开始",Thread.currentThread ());
try {
r.lock ();
test ();
r.lock ();
logger.info ("{}: 又开始",Thread.currentThread ());
test ();
r.unlock ();
} catch ( InterruptedException e ) {
e.printStackTrace ();
} finally {
r.unlock ();
}
}
}.start ();
new Thread (){
@Override
public void run (){
logger.info ("{}: 开始",Thread.currentThread ());
try {
r.lock ();
test ();
} catch ( InterruptedException e ) {
e.printStackTrace ();
} finally {
r.unlock ();
}
}
}.start ();
}
}
运行结果
[Thread-1] INFO floyd.learn.lock.TestReenTrantLock - Thread[Thread-1,5,main]: 开始
[Thread-1] INFO floyd.learn.lock.TestReenTrantLock - Thread[Thread-1,5,main]: 执行了
[Thread-0] INFO floyd.learn.lock.TestReenTrantLock - Thread[Thread-0,5,main]: 开始
[Thread-1] INFO floyd.learn.lock.TestReenTrantLock - Thread[Thread-1,5,main]: 执行了完成
[Thread-0] INFO floyd.learn.lock.TestReenTrantLock - Thread[Thread-0,5,main]: 执行了
[Thread-0] INFO floyd.learn.lock.TestReenTrantLock - Thread[Thread-0,5,main]: 执行了完成
[Thread-0] INFO floyd.learn.lock.TestReenTrantLock - Thread[Thread-0,5,main]: 又开始
[Thread-0] INFO floyd.learn.lock.TestReenTrantLock - Thread[Thread-0,5,main]: 执行了
[Thread-0] INFO floyd.learn.lock.TestReenTrantLock - Thread[Thread-0,5,main]: 执行了完成
2、lockInterruptibly()
public class LearnLock {
private static Lock lock = new ReentrantLock ();
public void insert (Thread thread) throws InterruptedException {
lock.lockInterruptibly ();
try {
System.out.println ( thread.getName ()+"获得了锁");
long startTime = System.currentTimeMillis();
for (; ; ) {
if (System.currentTimeMillis() - startTime >= Integer.MAX_VALUE){
break;
}
}
System.out.println ("业务执行完");
} catch ( Exception e ){
e.printStackTrace ();
} finally {
lock.unlock ();
System.out.println (thread.getName ()+"释放了锁");
}
}
public static void main ( String[] args ) {
LearnLock lock1 = new LearnLock ();
LeThreadExtend test1 = new LeThreadExtend (lock1);
LeThreadExtend test2 = new LeThreadExtend (lock1);
test1.start ();
test2.start ();
try {
Thread.sleep (2000);
} catch ( InterruptedException e ) {
e.printStackTrace ();
}
//test2.interrupt() 可以注释掉执行一次,看看结果,对比一下
test2.interrupt ();
System.out.println ("执行完。。");
}
}
3、tryLock
public class TestTryLock {
private static ArrayList<Integer> arrayList = new ArrayList<Integer>();
static Lock lock = new ReentrantLock ();
public static void main(String[] args) {
new Thread(){
@Override
public void run(){
Thread thread = Thread.currentThread();
boolean tryLock = false;
try {
tryLock = lock.tryLock(3, TimeUnit.SECONDS);
System.out.println(thread.getName()+" "+tryLock);
if (tryLock) {
Thread.sleep (2000);
System.out.println(thread.getName() + "拿到了锁");
for(int i = 0;i<10;i++){
arrayList.add(i);
}
lock.unlock();
System.out.println(thread.getName()+"释放了锁");
}
} catch ( InterruptedException e ) {
e.printStackTrace ();
}
}
}.start();
new Thread(){
@Override
public void run(){
Thread thread = Thread.currentThread();
//boolean tryLock = lock.tryLock();
boolean tryLock = false;
try {
tryLock = lock.tryLock(3, TimeUnit.SECONDS);
System.out.println(thread.getName()+" "+tryLock);
if (tryLock) {
Thread.sleep (2000);
System.out.println(thread.getName() + "拿到了锁");
for(int i = 0;i<10;i++){
arrayList.add(i);
}
lock.unlock();
System.out.println(thread.getName()+"释放了锁");
}
} catch ( InterruptedException e ) {
e.printStackTrace ();
}
}
}.start();
}
}
ReadWriteLock
ReadWriteLock 接口提供了读锁和写锁两个方法,ReentrantReadWriteLock是其实现类。多个线程可以同时申请读锁,但是在申请写锁时,需要等待所有的读锁全部释放后才可以申请成功。
public class TestReadWriteLock {
public static void main ( String[] args ) {
ReadWriteLock rw = new ReentrantReadWriteLock ();
TestReadWriteLock test = new TestReadWriteLock ();
new Thread (){
@Override
public void run(){
test.read (rw,Thread.currentThread ());
test.write (rw,Thread.currentThread ());
}
}.start ();
new Thread (){
@Override
public void run(){
test.read (rw,Thread.currentThread ());
test.write (rw,Thread.currentThread ());
}
}.start ();
}
public void read (ReadWriteLock rw,Thread thread){
try {
rw.readLock ().lock ();
System.out.println (thread.getName ()+"> 开始读取"+System.currentTimeMillis ());
Thread.sleep (2000);
System.out.println (thread.getName ()+"> 读取结束"+System.currentTimeMillis ());
} catch ( Exception e) {
e.printStackTrace ();
} finally {
rw.readLock ().unlock ();
System.out.println (thread.getName ()+"> 读取锁释放了"+System.currentTimeMillis ());
}
}
public void write(ReadWriteLock rw,Thread thread){
try {
rw.writeLock ().lock ();
System.out.println (thread.getName ()+"> 开始写入");
Thread.sleep (5000);
System.out.println (thread.getName ()+"> 写入结束");
} catch ( Exception e ) {
e.printStackTrace ();
} finally {
rw.writeLock ().unlock ();
System.out.println (thread.getName ()+"> 写入锁释放了");
}
}
}