Java-Lock接口、重入锁、读写锁
一、Lock接口
Lock接口是JDK1.5加入的,与synchronized比较,显示定义,结构更灵活
提供更多实用性方法,功能更强大、性能更优越
常用方法:
void lock();//获取锁,如果锁被占用,则等待
boolean tryLock()//尝试获取锁(成功返回true,失败返回false,不阻塞)
void unlock()//释放锁
二、重入锁
ReentrantLock:Lock接口的实现类,与synchronized一样具有互斥锁功能。
案例:重入锁 ReentrantLock 的使用
package com.monv.chatper14_1; /** * 重入锁 ReentrantLock的使用 */ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class MyList { private String[] str = {"A","B","","",""}; private int count = 2; //创建锁 private Lock lock = new ReentrantLock(); //添加元素 public void add(String value) { lock.lock(); try { str[count] = value; try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"添加了"+value); count++; } finally { lock.unlock(); } } public String[] getStr() { return str; } } --------------------测试-------------------------------------- package com.monv.chatper14_1; import java.util.Arrays; public class TestMyList { public static void main(String[] args) throws Exception{ MyList list1 = new MyList(); Runnable runnable = new Runnable() { @Override public void run() { list1.add("Hello"); } }; Runnable runnable2 = new Runnable() { @Override public void run() { list1.add("World"); } }; //定义线程 Thread t1 = new Thread(runnable); Thread t2 = new Thread(runnable2); //启动线程 t1.start(); t2.start(); t1.join(); t2.join(); System.out.println(Arrays.toString(list1.getStr())); } } ---------------------------------------
案例2:卖票的案例
package com.monv.chatper14_1; /** * 卖票案例 * @author Monv * */ import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class Ticket implements Runnable{ private int ticket = 100; private Lock lock = new ReentrantLock (); @Override public void run() { while(true) { lock.lock(); try { if (ticket<=0) { break; } System.out.println(Thread.currentThread().getName()+"卖了第"+ticket+"张票"); ticket--; } finally { lock.unlock(); } } } } -----------------------------测试------------------------------ package com.monv.chatper14_1; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class TestTicket { public static void main(String[] args) { Ticket tk = new Ticket(); //用线程池的方法卖票 //创建一个线程池 ExecutorService es = Executors.newFixedThreadPool(4); for (int i =0;i<4;i++) { es.submit(tk); } es.shutdown(); } } --------------------------------------------------------------
三、读写锁
ReentrantReadWriteLock:
一种支持一写多读的同步锁,读写分离,可分别分配读锁、写锁。
支持多次分配读锁,使多个读操作可以并发执行。
互斥规则:
写——写:互斥、堵塞
读——写:互斥,读堵塞写、写堵塞读
读——读:不互斥、不阻塞
在读操作远远高于写操作的环境中,可在保障线程安全的情况下,提高运行效率
es.isTerminated() : 判断线程是否全部执行完毕
案例:读写锁的使用
package com.monv.chatper14_1; /** * 演示读写锁的使用 * ReentrantReadWriteLock * @author Monv * */ import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock; import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock; public class ReadWriteDemo { //1.创建读写锁 private ReentrantReadWriteLock rrwl = new ReentrantReadWriteLock(); //创建读锁 private ReadLock readl = rrwl.readLock(); //创建写锁 private WriteLock writel = rrwl.writeLock(); private String value; //写入 public void setValue(String value) { writel.lock(); try { try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("写入操作:"+value); this.value = value; } finally { writel.unlock(); } } //读取 public String getValue() { readl.lock(); try { try { Thread.sleep(1000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println("读取操作:"+this.value); return this.value; } finally { readl.unlock(); } } } ---------------------------测试---------------------------- package com.monv.chatper14_1; /** * 读写锁 */ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class TestReadWrite { public static void main(String[] args) { ReadWriteDemo rwd = new ReadWriteDemo(); //创建线程池 ExecutorService es = Executors.newFixedThreadPool(20); //两个功能写和读 Runnable write = new Runnable() { @Override public void run() { rwd.setValue("这是一个写的操作"); } }; Runnable read = new Runnable() { @Override public void run() { rwd.getValue(); } }; long beg = System.currentTimeMillis(); //分配2个写的任务 for (int i =0;i<2;i++) { es.submit(write); } //分配18个读的任务 for(int i = 0;i<18 ;i++) { es.submit(read); } //结束线程池 es.shutdown(); while (!es.isTerminated()) {//如果线程未全部结束,则空转等待 } long end = System.currentTimeMillis(); System.out.println("用时:"+(end - beg )); } } -----------------------------------------------------------
输出是最好的输入。把学习的内容输出出来,加深记忆;