之前看过的一篇关于源码的实现,以及可以又学习到了很多公平锁以及非公平锁哦:
https://blog.csdn.net/lsgqjh/article/details/63685058
笔记:
Lock接口中每个方法的使用: lock()、tryLock()、tryLock(long time, TimeUnit unit)、lockInterruptibly()是用来获取锁的。 unLock()方法是用来释放锁的。 四个获取锁方法的区别: lock()方法是平常使用得最多的一个方法,就是用来获取锁。如果锁已被其他线程获取,则进行等待。 由于在前面讲到如果采用Lock,必须主动去释放锁,并且在发生异常时,不会自动释放锁。因此一般来说,使用Lock必须在try{}catch{}块中进行,并且将释放锁的操作放在finally块中进行,以保证锁一定被被释放,防止死锁的发生。 tryLock()方法是有返回值的,它表示用来尝试获取锁,如果获取成功,则返回true,如果获取失败(即锁已被其他线程获取),则返回false,也就说这个方法无论如何都会立即返回。在拿不到锁时不会一直在那等待。 tryLock(long time, TimeUnit unit)方法和tryLock()方法是类似的,只不过区别在于这个方法在拿不到锁时会等待一定的时间,在时间期限之内如果还拿不到锁,就返回false。如果如果一开始拿到锁或者在等待期间内拿到了锁,则返回true。 lockInterruptibly()方法比较特殊,当通过这个方法去获取锁时,如果线程正在等待获取锁,则这个线程能够响应中断,即中断线程的等待状态。也就使说,当两个线程同时通过lock.lockInterruptibly()想获取某个锁时,假若此时线程A获取到了锁,而线程B只有在等待,那么对线程B调用threadB.interrupt()方法能够中断线程B的等待过程。 注意,当一个线程获取了锁之后,是不会被interrupt()方法中断的。 因此当通过lockInterruptibly()方法获取某个锁时,如果不能获取到,只有进行等待的情况下,是可以响应中断的。 而用synchronized修饰的话,当一个线程处于等待某个锁的状态,是无法被中断的,只有一直等待下去。 ReentrantLock 直接使用lock接口的话,我们需要实现很多方法,不太方便,ReentrantLock是唯一实现了Lock接口的类,并且ReentrantLock提供了更多的方法,ReentrantLock,意思是“可重入锁”。
Lock:
public class MyLockTest { private static ArrayList<Integer> arrayList = new ArrayList<Integer>(); static Lock lock = new ReentrantLock(); // 注意这个地方 public static <E> void main(String[] args) { new Thread() { public void run() { Thread thread = Thread.currentThread(); lock.lock(); // 阻塞式的 try { System.out.println(thread.getName() + "得到了锁"); for (int i = 0; i < 5; i++) { arrayList.add(i); } } catch (Exception e) { // TODO: handle exception } finally { System.out.println(thread.getName() + "释放了锁"); lock.unlock(); } }; }.start(); new Thread() { public void run() { Thread thread = Thread.currentThread(); lock.lock(); try { System.out.println(thread.getName() + "得到了锁"); for (int i = 0; i < 5; i++) { arrayList.add(i); } } catch (Exception e) { // TODO: handle exception } finally { System.out.println(thread.getName() + "释放了锁"); lock.unlock(); } }; }.start(); } }
tryLock:(注意:trylock这个方法里面也可以加一个时间以及单位作为参数的)
/** * 观察现象:一个线程获得锁后,另一个线程取不到锁,不会一直等待 * @author * */ public class MyTryLock { private static ArrayList<Integer> arrayList = new ArrayList<Integer>(); static Lock lock = new ReentrantLock(); // 注意这个地方 public static void main(String[] args) { new Thread() { public void run() { Thread thread = Thread.currentThread(); boolean tryLock = lock.tryLock(); // 非阻塞式的 System.out.println(thread.getName()+" "+tryLock); if (tryLock) { try { System.out.println(thread.getName() + "得到了锁"); for (int i = 0; i < 5; i++) { arrayList.add(i); } } catch (Exception e) { // TODO: handle exception } finally { System.out.println(thread.getName() + "释放了锁"); lock.unlock(); } } }; }.start(); new Thread() { public void run() { Thread thread = Thread.currentThread(); boolean tryLock = lock.tryLock(); System.out.println(thread.getName()+" "+tryLock); if (tryLock) { try { System.out.println(thread.getName() + "得到了锁"); for (int i = 0; i < 5; i++) { arrayList.add(i); } } catch (Exception e) { // TODO: handle exception } finally { System.out.println(thread.getName() + "释放了锁"); lock.unlock(); } } }; }.start(); } }
lockInterruptibly():
/** * 观察现象:如果thread-0得到了锁,阻塞。。。 * thread-1尝试获取锁,如果拿不到,会等待,但是可以被中断等待 * @author * */ public class MyInterruptibly { private Lock lock = new ReentrantLock(); public static void main(String[] args) { MyInterruptibly test = new MyInterruptibly(); MyThread thread0 = new MyThread(test); MyThread thread1 = new MyThread(test); thread0.start(); thread1.start(); try { Thread.sleep(2000); // (1)等了两秒钟之后,如果还thread1还拿不到锁 } catch (InterruptedException e) { e.printStackTrace(); } // (2)就中断他呗,注意:lockInterruptibly()只有这个方法才是可中断的 thread1.interrupt(); //调用中断方法来测试能否中断等待中的线程 System.out.println("====================="); } public void insert(Thread thread) throws InterruptedException{ lock.lockInterruptibly(); //注意,如果需要正确中断等待锁的线程,必须将获取锁放在外面,然后将InterruptedException抛出 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 MyInterruptibly test = null; public MyThread(MyInterruptibly test) { this.test = test; } @Override public void run() { try { test.insert(Thread.currentThread()); } catch (Exception e) { // 一旦中断,就立刻抛个异常了 System.out.println(Thread.currentThread().getName()+"被中断"); } } }
读写锁:
利用synchronized
/** * 一个线程又要读又要写,用synchronize来实现的话,读写操作都只能锁住后一个线程一个线程地进行 * * @author * */ public class MySynchronizedReadWrite { public static void main(String[] args) { final MySynchronizedReadWrite test = new MySynchronizedReadWrite(); new Thread() { public void run() { test.operate(Thread.currentThread()); }; }.start(); new Thread() { public void run() { test.operate(Thread.currentThread()); }; }.start(); } public synchronized void operate(Thread thread) { long start = System.currentTimeMillis(); int i = 0; while (System.currentTimeMillis() - start <= 1) { i++; if (i % 4 == 0) { System.out.println(thread.getName() + "正在进行写操作"); } else { System.out.println(thread.getName() + "正在进行读操作"); } } System.out.println(thread.getName() + "读写操作完毕"); } }
ReentrantReadWriteLock
/** * 使用读写锁,可以实现读写分离锁定,读操作并发进行,写操作锁定单个线程 * * 如果有一个线程已经占用了读锁,则此时其他线程如果要申请写锁,则申请写锁的线程会一直等待释放读锁。 * 如果有一个线程已经占用读锁,其他线程还是申请读锁,则可以并发进行 * 如果有一个线程已经占用了写锁,则此时其他线程如果申请写锁或者读锁,则申请的线程会一直等待释放写锁。 * @author * */ public class MyReentrantReadWriteLock { private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock(); public static void main(String[] args) { final MyReentrantReadWriteLock test = new MyReentrantReadWriteLock(); new Thread(){ public void run() { test.get(Thread.currentThread()); test.write(Thread.currentThread()); }; }.start(); new Thread(){ public void run() { test.get(Thread.currentThread()); test.write(Thread.currentThread()); }; }.start(); } /** * 读操作,用读锁来锁定 * @param thread */ public void get(Thread thread) { rwl.readLock().lock(); try { long start = System.currentTimeMillis(); while(System.currentTimeMillis() - start <= 1000) { System.out.println(thread.getName()+"正在进行读操作"); Thread.sleep(100); } System.out.println(thread.getName()+"读操作完毕"); }catch(Exception e){ } finally { rwl.readLock().unlock(); } } /** * 写操作,用写锁来锁定 * @param thread */ public void write(Thread thread) { rwl.writeLock().lock();; try { long start = System.currentTimeMillis(); while(System.currentTimeMillis() - start <= 1) { System.out.println(thread.getName()+"正在进行写操作"); } System.out.println(thread.getName()+"写操作完毕"); } finally { rwl.writeLock().unlock(); } } }
END!