Java中Lock锁接口和实现类详解

1. Lock接口

public interface Lock {}
  • 提供更多实用性方法,功能更强大、性能更优越。
    常用方法:
    ① void lock() // 获取锁,如锁被占用,则等待
    ② boolean trylock() // 尝试获取锁(成功true,失败false,不阻塞)
    ③ void unlock() // 释放锁

2. ReentrantLock类(重入锁/递归锁) - Lock接口实现类

public class ReentrantLock extends Object implements Lock, Serializable
  • Lock接口的实现类,与synchronized一样具有互斥锁功能。
    注意:
    1)使用Lock,需要显式的获取锁和释放锁;
    2)为了避免拿到锁的线程在运行期间出现异常,导致程序终止没有释放锁!应用try-finally来保证无论是否出现异常,最终必须释放锁;
    3)ReentrantLock为重入锁,避免递归,如果必须递归,必须正确控制退出条件。
    (此锁支持同一线程的2147483647个递归锁的最大值。试图在Error超过这个限制的结果将从锁定的方法。)
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class TestLocks {
      public static void main(String[] args) {
            Test obj = new Test();
            Thread t1 = new Thread(new MyTask(obj));
            Thread t2 = new Thread(new MyTask2(obj));
            
            t1.start();
            t2.start();
      }
}
class Test{
      Lock lock = new ReentrantLock(); // 可重入锁
      public void method() {
            System.out.println(Thread.currentThread().getName() + "进入上锁的方法中...");
            try {
                  lock.lock(); // 获取锁(显式)
                  try {
                        Thread.sleep(2000);
                  } catch (InterruptedException e) {
                        e.printStackTrace();
                  }
                  //method(); //不要出现无穷递归,容易内存溢出导致锁一直没有释放。
                  System.out.println(Thread.currentThread().getName() +  "退出上锁的方法中...");
            } finally {
                  lock.unlock(); // 释放锁(显式) + 切记finally释放资源
            }
      }
}
class MyTask implements Runnable {
      Test obj;
      public MyTask(Test obj) {
            super();
            this.obj = obj;
      }
      @Override
      public void run() {
            obj.method();
      }
}
class MyTask2 implements Runnable {
      Test obj;
      public MyTask2(Test obj) {
            super();
            this.obj = obj;
      }
      @Override
      public void run() {
            obj.method();
      }
}

3. ReentrantReadWriteLock类(读写锁) - ReadWriteLock接口实现类

public class ReentrantReadWriteLock extends Object implements ReadWriteLock, Serializable
  • 一种支持一写多读的同步锁,读写分离,可分别分配读锁、写锁;
  • 支持多次分配读锁,使多个读操作可以并发执行(写锁同步,读锁异步)。
    互斥规则:
    ① 写-写:互斥,阻塞;
    ② 读-写:互斥,读阻塞写、写阻塞读;
    ③ 读-读:不互斥、不阻塞;
  • 在读操作远远高于写操作的环境下,可在保证线程安全的情况下,提高运行效率。
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
public class TestReadWriteLock {
      public static void main(String[] args) {
            Student s = new Student();
            ExecutorService es = Executors.newFixedThreadPool(20);
            WriteTask write = new WriteTask(s);
            ReadTask read = new ReadTask(s);
            
            long start = System.currentTimeMillis();
            es.submit(write);
            es.submit(write);
            
            for (int i = 1; i <= 18; i++) {
                  es.submit(read);
            }
            
            es.shutdown();
            while(true) {
                  System.out.println("结束了吗?");
                  if (es.isTerminated() == true) {
                        break;
                  }
            }
            
            long end = System.currentTimeMillis();
            System.out.println("运行时间:" + (end-start));
      }
}
class WriteTask implements Callable<Object> {
      Student stu;
      public WriteTask(Student stu) {
            this.stu = stu;
      }
      @Override
      public Object call() throws Exception {
            this.stu.setAge(20);
            return null;
      }
}
class ReadTask implements Callable<Object> {
      Student stu;
      public ReadTask(Student stu) {
            this.stu = stu;
      }
      @Override
      public Object call() throws Exception {
            this.stu.getAge();
            return null;
      }
}
class Student {
      private int age;
      //Lock lock = new ReentrantLock(); // 读写情况下都加锁,性能过低!
      ReentrantReadWriteLock rrwl = new ReentrantReadWriteLock(); // 有两把锁
      ReadLock read = rrwl.readLock(); // 读锁 - 内部类
      WriteLock write = rrwl.writeLock(); // 写锁 - 内部类
      // 赋值:写操作
      public void setAge(int age) throws InterruptedException {
            //lock.lock();
            write.lock();
            try {
                  Thread.sleep(1000);
                  this.age = age;
            } finally {
                  //lock.unlock();
                  write.unlock();
            }
      }
      // 取值:读操作
      public int getAge() throws InterruptedException {
            //lock.lock();
            read.lock();
            try {
                  Thread.sleep(1000);
                  return this.age;
            } finally {
                  //lock.unlock();
                  read.lock();
            }
      }
}
// Lock互斥锁运行时间20034毫秒,ReadWriteLock读写锁运行时间3004毫秒
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容