Java Lock的使用
来源:互联网 发布:淘宝宝贝截图 编辑:程序博客网 时间:2024/05/16 08:57
首先扯点别的:记得以前在大学校里和同学一起打勾级,我怂恿我的队友杜仁建出牌,硬说我队友的对门周通要不了杜仁建的牌,原话是这样的“他(周通)要是能要了,我把牌吃了吐出来再吃”。结果他(周通)还是把我队友(杜仁建)给闷了。现在想想也是有意思。
今天记录一下Java中同步锁的使用。以后再慢慢理解。
首先看一下Lock这个接口,在java.util.concurrent.locks.Lock
包下面,ReentrantLock:可重入锁,实现了Lock接口。
public interface Lock { void lock(); void lockInterruptibly() throws InterruptedException; boolean tryLock(); boolean tryLock(long time, TimeUnit unit) throws InterruptedException; //释放锁 void unlock(); //返回一个和当前锁关联的Condition对象 Condition newCondition();
解释一下上面几个方法的作用
void lock();
获取锁,如果锁不可用,当前线程则不能被线程调度,并处于休眠状态,直到获得锁。
void lockInterruptibly() throws InterruptedException;
获取锁,如果锁可用则立即返回。如果锁不可用,当前线程则不能被线程调度,并处于休眠状态,直到下面两种情况之一发生。
1. 当前线程获取到锁。
2. 当前线程被中断,抛出InterruptedException。
boolean tryLock();
如果能够获取锁,立即返回true,否则立即返回false。使用tryLock( )惯用语法。
Lock lock = ...; if (lock.tryLock()) { try { // 获取成功操作 } finally { lock.unlock(); } } else { //获取失败操作 }}
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
- 如果能够获取锁,方法立即返回true。
- 如果锁不可用,当前线程会一直休眠等待直到下面三种情况中的一种情况发生。
- 当前线程成功获取了锁,返回true。
- 当前线程被其他线程中断,抛出InterruptedException异常。
- 等待时间超时,返回false。
ReentrantLock类中其他方法
//判断锁是否被线程持有 public boolean isLocked() { return sync.isLocked(); }//判断当前锁是否是公平锁public final boolean isFair() { return sync instanceof FairSync;}
具体的使用方法
lock()方法
public class Test { private ArrayList<Integer> list = new ArrayList<>(); private Lock lock = new ReentrantLock(); public static void main(String[] args) { Test test = new Test(); new Thread(new Runnable() { @Override public void run() { test.insert(Thread.currentThread()); } }).start(); new Thread(new Runnable() { @Override public void run() { test.insert(Thread.currentThread()); } }).start(); } public void insert(Thread t) { lock.lock(); try { System.out.println(t.getName() + "得到了锁"); for (int i = 0; i < 5; i++) { list.add(i); } } finally { System.out.println(t.getName() + "释放了锁"); lock.unlock(); } }}
输出结果
Thread-0得到了锁Thread-0释放了锁Thread-1得到了锁Thread-1释放了锁
tryLock()方法
public class Test { private Lock lock = new ReentrantLock(); public static void main(String[] args) { Test test = new Test(); new Thread(new Runnable() { @Override public void run() { test.insert(Thread.currentThread()); } }).start(); new Thread(new Runnable() { @Override public void run() { test.insert(Thread.currentThread()); } }).start(); } public void insert(Thread t) { if (lock.tryLock()) { try { System.out.println(t.getName() + "得到了锁"); try { //睡眠一会,但是不释放锁 Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } finally { System.out.println(t.getName() + "释放了锁"); lock.unlock(); } } else { System.out.println(t.getName() + "获取锁失败"); } }}
输出结果
Thread-0得到了锁Thread-1获取锁失败Thread-0释放了锁
lockInterruptibly()方法
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(); //延迟一会再启动线程2,否则可能出现线程2先被调度执行,那么线程2就不能被中断了 try { Thread.sleep(2000); System.out.println("启动线程" + thread2.getName()); thread2.start(); } catch (InterruptedException e) { e.printStackTrace(); } 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() + "被中断"); } }}
输出结果
Thread-0获得了锁Thread-1被中断
当thread1启动后,获得了锁。两秒后再启动thread2,然后thread2尝试获取锁,这时候,thread1正在持有锁,所以thread2处于等待状态。然后又过了两秒,调用thread2.interrupt()方法,中断thread2,lock.lockInterruptibly();就会抛出中断异常,在捕获的异常中输出Thread-1被中断。
ReadWriteLock:读写锁,也是一个接口,在java.util.concurrent.locks.ReadWriteLock
包下,内部维持一对相关的锁。读锁,可以多个读者线程共用。写锁,互斥,同一时刻只能被一个线程使用。ReentrantReadWriteLock实现了这个接口。
public interface ReadWriteLock { //返回用来读的锁 Lock readLock(); //返回用来写的锁 Lock writeLock();}
public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable { //内部类,提供读锁 private final ReentrantReadWriteLock.ReadLock readerLock; //内部类,提供写锁 private final ReentrantReadWriteLock.WriteLock writerLock; //... //获取写锁 public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; } //获取读锁 public ReentrantReadWriteLock.ReadLock readLock() { return readerLock; } }
WriteLock的获取锁的方法,以最简单的lock( )方法为例
/** * 获取写锁 *如果读锁和写锁都没有被其他线程持有,则立即返回,并设置锁的计数为1。 *如果当前线程持有写锁,就把锁的计数加1,立即返回。 *如果写锁被其他线程持有,当前线程就不能被线程调度,并一直休眠,直到获取写锁(这时候写锁的计数为1) */ public void lock() { sync.acquire(1); }
ReadLock获取锁的方法,以最简单的lock( )方法为例
//获取读锁 //如果写锁没有没其他线程持有,则立即返回。 //如果写锁被别的线程持有,则当前线程不能被线程调度,并一直休眠直到获取到读锁。 public void lock() { sync.acquireShared(1); }
多个线程同时使用读锁
public class ReentrantReadWriteLockTest { private ReadWriteLock rwl = new ReentrantReadWriteLock(); public static void main(String[] args) { ReentrantReadWriteLockTest test = new ReentrantReadWriteLockTest(); new Thread() { public void run() { test.get(Thread.currentThread()); } }.start(); new Thread() { public void run() { test.get(Thread.currentThread()); } }.start(); } private void get(Thread thread) { rwl.readLock().lock(); try { long start = System.currentTimeMillis(); while (System.currentTimeMillis() - start < 1000) { System.out.println(thread.getName() + "正在进行读操作"); } System.out.println(thread.getName() + "读操作完毕"); } catch (Exception e) { e.printStackTrace(); } finally { rwl.readLock().unlock(); } }}
输出结果会发现两个线程会交替输出,意思就是多个线程可以同时共用读锁。
一个线程使用读锁,一个线程使用写锁。
如果有一个线程已经占用了读锁,则此时其他线程如果要申请写锁,则申请写锁的线程会一直等待释放读锁。如果有一个线程已经占用了写锁,则此时其他线程如果要申请读锁,则申请读锁的线程会一直等待释放写锁。
public class ReentrantReadWriteLockTest { private ReadWriteLock rwl = new ReentrantReadWriteLock(); public static void main(String[] args) { ReentrantReadWriteLockTest test = new ReentrantReadWriteLockTest(); new Thread() { public void run() { test.get(Thread.currentThread()); } }.start(); new Thread() { public void run() { test.write(Thread.currentThread()); } }.start(); } private void get(Thread thread) { rwl.readLock().lock(); try { long start = System.currentTimeMillis(); while (System.currentTimeMillis() - start < 100) { System.out.println(thread.getName() + "正在进行读操作"); } System.out.println(thread.getName() + "读操作完毕"); } catch (Exception e) { e.printStackTrace(); } finally { rwl.readLock().unlock(); } } private void write(Thread thread) { rwl.writeLock().lock(); try { long start = System.currentTimeMillis(); while (System.currentTimeMillis() - start < 100) { System.out.println(thread.getName() + "正在进行写操作"); } System.out.println(thread.getName() + "写操作完毕"); } catch (Exception e) { e.printStackTrace(); } finally { rwl.writeLock().unlock(); } }}
运行结果发现读和写是顺序执行的,也就是说,读锁和写锁是互斥的,同一时刻不能有一个线程使用读锁,一个线程使用写锁。
结尾:先记录下来,以后再慢慢体会,完善。
参考
【1】http://www.cnblogs.com/dolphin0520/p/3923167.html
【2】疯狂Java讲义
- java lock 的使用
- Java Lock的使用
- Lock的使用 java多线程
- Java中Lock的使用
- java 中Lock的使用
- Java多线程--Lock的使用
- java多线程Lock的使用。
- Java多线程之Lock的使用
- Java多线程之Lock的使用
- 黑马程序员 java Lock的使用
- JAVA多线程之Lock的使用
- Java中Synchronized和Lock的使用
- Java多线程之Lock的使用
- Java学习--多线程之Lock的使用
- Java多线程之Lock的使用
- Java—Lock&Condition的使用
- Java多线程之Lock的使用
- Java多线程之Lock的使用
- 程序员面试金典——n皇后问题_____(S)
- UDA1341(asoc)分析
- 【IO流】FileReader,FileWriter完成文件的copy
- Python入门学习(3)
- MySQL大数据量分页查询方法及其优化
- Java Lock的使用
- 5.activiti工作流-流程实例、任务的执行
- php 全局类介绍
- Django10-后台(Admin)
- C++中的引用与指针的区别
- Require模块入门一
- 洛谷P2801 教主的魔法 分块
- 表达式计算栈实现
- Ubuntu16.04环境下命令行安装驱动