zoukankan      html  css  js  c++  java
  • Java多线程学习篇(三)Lock

    Lock 是Java多线程的一个同步机制,用来控制线程对共享资源的访问。线程在执行同步方法或者代码块之前必须先获得一个锁。

    Lock 的 lock() 和 unlock() 方法;

      lock():获得一个锁,如果锁不可用,则当前线程将因线程调度目的而被禁用,并在获得锁之前处于休眠状态。

      unlock():释放掉获得的锁。

    Lock的作用范围:

    1. 若 Lock 是静态的,则作用范围是整个类。

      public class Test {
          public static void main(String[] args) {
              Thread thread_one = new Thread(new Account(), "Thread_ONE");
              Thread thread_two = new Thread(new Account(), "Thread_Tow");
              thread_one.start();
              thread_two.start();
          }
      }
      class Account implements Runnable{
          static Lock lock = new ReentrantLock();  // 静态的Lock
          static int Count = 0;
          @Override
          public void run(){
              runTest();
          }
          public void runTest() {
              lock.lock();
              try{
                  for(int i = 0; i < 5; ++i)
                  {
                      Count++;
                      System.out.println(Thread.currentThread().getName() + " " + Count);
                  }
              }
              finally {
                  lock.unlock();
              }
          }
      }
      //输出:
      //Thread_ONE 1
      //Thread_ONE 2
      //Thread_ONE 3
      //Thread_ONE 4
      //Thread_ONE 5
      //Thread_Tow 6
      //Thread_Tow 7
      //Thread_Tow 8
      //Thread_Tow 9
      //Thread_Tow 10
      静态的Lock
    2. 若 Lock 是非静态的,则范围是整个对象。

      import java.util.concurrent.locks.Lock;
      import java.util.concurrent.locks.ReentrantLock;
      
      public class Test1 {
          public static void main(String[] args) {
              Thread thread_one = new Thread(new Account(), "Thread_ONE");
              Thread thread_two = new Thread(new Account(), "Thread_Tow");
              thread_one.start();
              thread_two.start();
          }
      }
      class Account implements Runnable{
          Lock lock = new ReentrantLock();  // 非静态的Lock
          static int Count = 0;
          @Override
          public void run(){
              runTest();
          }
          public void runTest() {
              lock.lock();
              try{
                  for(int i = 0; i < 5; ++i)
                  {
                      Count++;
                      System.out.println(Thread.currentThread().getName() + " " + Count);
                  }
              }
              finally {
                  lock.unlock();
              }
          }
      }
      //输出:
      //Thread_Tow 2
      //Thread_ONE 2
      //Thread_Tow 3
      //Thread_ONE 4
      //Thread_Tow 5
      //Thread_ONE 6
      //Thread_Tow 7
      //Thread_ONE 8
      //Thread_Tow 9
      //Thread_ONE 10
      非静态的Lock

    Lock的一个简单的实现

    public class Lock{
        
        private boolean isLocked = false;
    
        public synchronized void lock()throws InterruptedException{
            while(isLocked){ // 使用whlie而不是if
                wait(); // 终止线程并且释放对象的锁,当线程被通知后重新启动,锁就会自动被重新获取
            }
            isLocked = true;
        }
        public synchronized void unlock(){
            isLocked = false;
            notify();//通知一个等待的线程重新获取锁并且恢复执行
        }
    }

    这里的方法lock(),若当前的锁被其它线程获取而锁住,这调用wait()方法,让线程等待,直到其他线程调用unlock()中的notify()方法而重新启动。这里用的是while而不是if,防止wait()退出后锁还是被其它线程锁住,(比如锁又被其它线程抢走),(lock() 和 notify()、notifyAll() 是Object对象中的方法)


    ReentrantLock 是 Lock接口 的一种实现。
    public class ReentrantLock implements Lock, java.io.Serializable{ }
    ReentrantLock 具有可重入性。
    什么是可可重入性呢?先举个例子。
    public class Reentrant2{
    
        Lock lock = new Lock(); // 这里的Lock用的是上面写的 public class Lock { }
    
        public outer(){
            lock.lock();
            inner();
            lock.unlock();
        }
    
        public synchronized inner(){
            lock.lock();
            //do something
            lock.unlock();
        }
    }
    假设某个线程调用了outer()方法,这时,该线程调用了lock(),获取了锁,然后再调用inner(),但是inner()内再次调用 lock() 获取锁,可是这锁已经被第一次调用而锁上,所以会进入while调用wait()从而导致死锁。
    可重入性可以让线程调用自身持有的锁(如果该锁是可重入的)。

    改写一下Lock的代码
    public class Lock{
    
        boolean isLocked = false;
        Thread  lockedBy = null;
        int     lockedCount = 0;
    
        public synchronized void lock()
                throws InterruptedException{
            Thread callingThread = Thread.currentThread();
            while(isLocked && lockedBy != callingThread){  // 若锁被不是自己持有的锁锁住
                wait();
            }
            isLocked = true;
            lockedCount++;
            lockedBy = callingThread;
        }
        
        public synchronized void unlock(){
            if(Thread.curentThread() == this.lockedBy){
                lockedCount--;
    
                if(lockedCount == 0){
                    isLocked = false;
                    notify();
                }
            }
        }
      ...
    }
    while 循环中加了一个判断 lockedBy != callingThread,这样就不会被自己的锁锁住,并且用 lockedCount 计数一下,只有当 lockedCount 为 0 时,才会调用notify()方法。

    最后说一点,使用锁的时候最好使用try,以防一些想不到的问题导致锁没有释放。
    lock.lock();
    try{
      //do critical section code, which may throw exception
    } finally {
      lock.unlock();
    }
    参考:http://tutorials.jenkov.com/java-concurrency/locks.html

  • 相关阅读:
    如何处理请求返回的二进制数据流转化成xlsx文件?
    iview 表单验证不通过问题?
    如何发布一个npm包?
    async 与 await
    数据库事务的四个基本特征以及事务的隔离级别
    遍历Map的四种方式
    HashMap详解
    HashMap和Hashtable的区别
    java中的堆、栈和常量池简介
    Spring IOC(转载)
  • 原文地址:https://www.cnblogs.com/lkcc/p/8254105.html
Copyright © 2011-2022 走看看