lock与synchronized的区别:
lock是一个接口,synchronized是关键字。前者可以程序员自己DIY功能,实现自定义同步组件;后者是JVM来维护的。
lock需要手动加解锁,synchronized自动完成加解锁。
synchronized修饰的代码执行异常时,自动释放线程占有的锁,不会出现死锁;lock异常时需在finally中unlock(),否则死锁。
lock可以让线程“在等待锁的过程中(即阻塞时)”响应中断,如tryLock;而synchronized在“等待锁的过程中(即阻塞时)”无法响应中断。
synchronized只能是非公平锁,而lock可公平和非公平。
lock可实现读写锁。
lock锁的范围有局限性,仅适用于代码块范围,而synchronized可以锁住代码块,对象实例,类。
lock可以绑定条件,实现分组唤醒需要的线程;synchronized要么随机唤醒一个,要么唤醒全部线程。
1 2 3 4 5 6 7 8 public interface Lock { void lock () ; void lockInterruptibly () throws InterruptedException ; boolean tryLock () ; boolean tryLock (long time, TimeUnit unit) throws InterruptedException ; void unlock () ; Condition newCondition () ; }
1 2 3 4 5 6 7 8 9 Lock lock = new LockImpl; lock.lock(); try { } catch (Exception ex) { } finally { lock.unlock(); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 import java.util.ArrayList;import java.util.List;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class ApplicationDemo { private List<Integer> arrayList = new ArrayList<>(); public static void main (String[] args) { ApplicationDemo applicationDemo = new ApplicationDemo(); Thread thread1 = new Thread(new Runnable() { @Override public void run () { applicationDemo.insert(Thread.currentThread()); } }); Thread thread2 = new Thread(new Runnable() { @Override public void run () { applicationDemo.insert(Thread.currentThread()); } }); thread1.start(); thread2.start(); } private void insert (Thread thread) { Lock lock = new ReentrantLock(); lock.lock(); try { System.out.println(thread.getName() + " get lock" ); thread.sleep(1000 ); } catch (Exception e) { } finally { System.out.println(thread.getName() + " unlock the lock" ); lock.unlock(); } } }
错误原因:
insert方法中lock变量为局部变量,每个线程获取到的是不同的锁,所以不会发生冲突。
lock正确使用方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 import java.util.ArrayList;import java.util.List;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class ApplicationDemo { private List<Integer> arrayList = new ArrayList<>(); private Lock lock = new ReentrantLock(); public static void main (String[] args) { ApplicationDemo applicationDemo = new ApplicationDemo(); Thread thread1 = new Thread(new Runnable() { @Override public void run () { applicationDemo.insert(Thread.currentThread()); } }); Thread thread2 = new Thread(new Runnable() { @Override public void run () { applicationDemo.insert(Thread.currentThread()); } }); thread1.start(); thread2.start(); } private void insert (Thread thread) { lock.lock(); try { System.out.println(thread.getName() + " get lock" ); thread.sleep(1000 ); } catch (Exception e) { } finally { System.out.println(thread.getName() + " unlock the lock" ); lock.unlock(); } } }
tryLock()方法,有返回值,尝试获取锁,获取成功返回true,获取失败(即锁被其他线程获取),返回false。也就是说,该方法无论能否拿到锁,都立即返回,不会拿不到锁的时候一直处于等待状态。
1 2 3 4 5 6 7 8 9 10 11 12 Lock lock = ...; if (lock.tryLock()) { try { } catch (Exception e) { ... } finally { lock.unlock(); } } else { }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public class Test { private ArrayList<Integer> arrayList = new ArrayList<Integer>(); private Lock lock = new ReentrantLock(); public static void main (String[] args) { final Test test = new Test(); new Thread() { public void run () { test.insert(Thread.currentThread()); } }.start(); new Thread() { public void run () { test.insert(Thread.currentThread()); } }.start(); } public void insert (Thread thread) { if (lock.tryLock()) { try { System.out.println(thread.getName() + "得到了锁" ); for (int i = 0 ; i < 5 ; ++i) { arrayList.add(i); } } catch (Exception e) { } finally { System.out.println(thread.getName() + "释放了锁" ); lock.unlock(); } } else { System.out.println(thread.getName() + "获取锁失败" ); } } }
lockInterruptibly()方法,可以在线程“等待获取锁”时响应中断,抛出InterruptedException异常。
1 2 3 4 5 6 7 8 public void method () throws InterruptedException { lock.lockInterruptibly(); try { } finally { lock.unlock(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 public class Test { private Lock lock = new ReentrantLock(); public static void main (String[] args) { Test test = new Test(); Mythread thread1 = new MyThread(test); Mythread thread2 = new MyThread(test); thread1.start(); thread2.start(); try { Thread.sleep(2000 ); } catch (InterruptedException e) { e.printStackTrace(); } thread2.interrupt(); } 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 ; } } finally { System.out.println(Thread.currentThread().getName() + "执行finally" ); lock.unlock(); System.out.println(thread.getName() + "释放了锁" ); } } } class Mythread extends Thread { private Test test = null ; public Mythread (Test test) { this .test = test; } @Override public void run () { try { test.insert(Thread.currentThread()); } catch (InterruptedException e) { System.out.println(Thread.currentThread().getName() + "被中断" ); } } }
ReentrantLock
可重入锁,即支持一个线程对相同资源重复加锁。实现可重入需解决两个问题:
1、锁需要去识别获取锁的线程是否为当前占据锁的线程,如果是,则可再次成功获取。
2、同一线程对同一资源锁的获取和释放,通过计数的方式来实现。
ReadWriteLock读写锁的接口,里面只定义了两个方法,一个用来获取读锁,一个用来获取写锁,即实现两个分开的锁,可分配给多个线程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 public interface ReadWriteLock { Lock readLock () ; Lock writeLock () ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 public class Test { public static void main (String[] args) { final Test test = new Test(); new Thread() { public void run () { test.get(Thread,currentThread()); } }.start(); new Thread() { public void run () { test.get(Thread,currentThread()); } }.start(); } public synchronized void get (Thread thread) { long start = System.currentTimeMillis(); while (System.currentTimeMillis() - start <= 1 ) { System.out.println(thread.getName() + "正在进行读操作" ); } System.out.println(thread.getName() + "读操作完毕" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 public class Test { private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); public static void main (String[] args) { final Test test = new Test(); new Thread() { public void run () { test.get(Thread.currentThread()); } }.start(); new Thread() { public void run () { test.get(Thread.currentThread()); } }.start(); } public void get (Thread thread) { rwl.readLock.lock(); try { long start = System.currentTimeMillis(); while (System.currentTimeMillis() - start <= 1 ) { System.out.println(thread.getName() + "正在进行读操作" ); } System.out.println(thread.getName() + "读操作完毕" ); } finally { rwl.readLock().unlock(); } } }
1 ReentrantLock lock = new ReentrantLock(true );
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 import java.util.concurrent.locks.Condition;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;public class ShareResource { private volatile int num = 1 ; private Lock lock = new ReentrantLock(); private Condition conditionA = lock.newCondition(); private Condition conditionB = lock.newCondition(); private Condition conditionC = lock.newCondition(); public void print5 () { lock.lock(); try { while (num != 1 ) { conditionA.await(); } for (int i = 0 ; i < 5 ; ++i) { System.out.println(Thread.currentThread().getName() + " " + (i + 1 )); } num = 2 ; conditionB.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } public void print10 () { lock.lock(); try { while (num != 2 ) { conditionB.await(); } for (int i = 0 ; i < 10 ; ++i) { System.out.println(Thread.currentThread().getName() + " " + (i + 1 )); } num = 3 ; conditionC.signal(); } catch (InterruptedException e) { e.printStackTrace(); } fianlly { lock.unlock(); } } public void print15 () { lock.lock(); try { while (num != 3 ) { conditionC.await(); } for (int i = 0 ; i < 15 ; ++i) { System.out.println(Thread.currentThread().getName() + " " + (i + 1 )); } num = 1 ; conditionA.signal(); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } } } public class ApplicationDemo { public static void main (String[] args) { ShareResource shareResource = new ShareResource(); Thread threadA = new Thread(new Runnable() { @Override public void run () { for (int i = 0 ; i < 3 ; ++i) { sharedResource.print5(); } } }, "A" ); Thread threadB = new Thread(new Runnable() { @Override public void run () { for (int i = 0 ; i < 3 ; ++i) { sharedResource.print10(); } } }, "B" ); Thread threadC = new Thread(new Runnable() { @Override public void run () { for (int i = 0 ; i < 3 ; ++i) { sharedResource.print15(); } } }, "C" ); threadA.start(); threadB.start(); threadC.start(); } }
摘自/参考链接1
摘自/参考链接2
摘自/参考链接3