zoukankan      html  css  js  c++  java
  • JAVA 锁

    JAVA 锁

    锁的概念

    Java中的锁是控制资源访问的一种方式。它弥补了synchronized的可操作性不强的不足。
    Java的锁都实现了Lock接口。Lock结构定义了锁的基本操作。

    函数 解释
    void lock() 获取锁,如果锁被其他线程占用,则等待
    void lockInterruptibly() throws InterruptedException 获取锁,如果锁被其他线程占用,则等待。当该线程处于等待状态的时候,可以被interrupt()中断
    boolean tryLock() 尝试获取锁,如果成功,返回true,如果失败,返回false
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException; 与tryLock的不同是,使用该方法,如果无法获取锁,会等待一段时间,在这段时间内,如果无法获取,则返回false。
    Condition newCondition() 与wait,notify 类似,必须和锁一起配合使用

    lock的基本用法:

      Lock lock = new ***();
      lock.lock();
      try {
      //业务逻辑
      } finally {
      lock.unlock();
      }
    

    tryLock 的基本用法:

    Lock lock = ***;
    if(lock.tryLock()) {
         try{
             //处理业务
         }catch(Exception ex){
             
         }finally{
             lock.unlock();   
         } 
    }else {
        //获取不到锁,做其他业务
    }
    

    lockInterruptibly 的基本用法:

    https://www.zhihu.com/question/36771163

    package com.thread;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class TestLockInterruptibly
    {
    
        // @Test
        public void test3() throws Exception
        {
            final Lock lock = new ReentrantLock();
            lock.lock();
    
            Thread t1 = new Thread(new Runnable()
            {
                @Override
                public void run()
                {
                    try
                    {
                        lock.lockInterruptibly();
                    }
                    catch(InterruptedException e)
                    {
                        System.out.println(Thread.currentThread().getName() + " interrupted.");
                    }
                }
            }, "child thread -1");
    
            t1.start();
            Thread.sleep(1000);
    
            t1.interrupt();
    
            Thread.sleep(1100);
        }
    
        public static void main(String[] args) throws Exception
        {
            new TestLockInterruptibly().test3();
        }
    }
    
    

    上面是Lock接口的基本介绍,在实际使用中,主要有一下几种锁:

    • 重入锁
    • 读写锁

    这些锁实现了Lock接口,为用户提供了统一的调用方法。内部实现基本都是通过聚合了一个队列同步器AbstractQueuedSynchronizer的子类来完成线程访问控制的。

    ReentrantLock

    ReentrantLock是一个重入锁,它表示该锁能够支持一个线程对资源的重复加锁。ReentrantLock还支持公平和非公平。

    package com.thread;
    
    import java.util.*;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    
    public class FairAndUnfairTest {
    
        private static Lock fairLock = new ReentrantLock2(true);
        private static Lock unfairLock = new ReentrantLock2(false);
    
    
        public void fair() {
            testLock(fairLock);
        }
    
    
        public void unfair() {
            testLock(unfairLock);
        }
    
        public void testLock(Lock lock) {
            for (int i = 0 ; i < 5; i++) {
                Job job = new Job(lock);
                job.start();
            }
    
        }
    
    
        private static class Job extends Thread {
            private Lock lock;
            public Job(Lock lock) {
                this.lock = lock;
            }
            public void run() {
                lock.lock();
                try {
                    System.out.print("current thread name is: " + this.getName());
                    print_list(lock);
                } finally {
                    lock.unlock();
                }
                lock.lock();
                try {
                    System.out.print("current thread name is: " + this.getName());
                    print_list(lock);
                } finally {
                    lock.unlock();
                }
    
            }
    
            private void print_list(Lock lock) {
                ReentrantLock2 t_lock = (ReentrantLock2)lock;
                Collection<Thread> threads = t_lock.getQueuedThreads();
                System.out.print(" the thread in queue is : ");
                for (Thread t : threads) {
                    System.out.print(t.getName() + ' ');
                }
                System.out.print('
    ');
            }
    
        }
    
        private static class ReentrantLock2 extends ReentrantLock {
    
            public ReentrantLock2(boolean fair) {
                super(fair);
            }
    
            public Collection<Thread> getQueuedThreads() {
                List<Thread> arrayList = new ArrayList<Thread>(super.getQueuedThreads());
    
    
                Collections.reverse(arrayList);
                return arrayList;
            }
        }
    
        public static void main(String[] args) {
            FairAndUnfairTest test = new FairAndUnfairTest();
            test.unfair();
    
        }
    }
    
    

    ReentrantLock通过在构造函数中传入true和false设置为公平或者非公平。如果是公平锁,就会每次从等待队列中获取最前的线程使用锁,否则就当前线程很可能再次获得锁。
    公平锁有助于平均分配资源,但是线程不断切换会造成更多的开销。

    ReentrantReadWriteLock

    读写锁在同一个时刻允许多个读线程进行访问,但是在写线程访问的时候,所有的读线程和其它写线程均被阻塞。

     package com.thread;
    
    import java.util.HashMap;
    import java.util.Map;
    import java.util.Objects;
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    
    public class Cache {
        static Map<String, Object> map = new HashMap<String, Object>();
    
        static ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    
        static Lock r = rwl.readLock();
        static Lock w = rwl.writeLock();
    
        public static final Object get(String key) {
            r.lock();
            try {
                return map.get(key);
            } finally {
                r.unlock();
            }
        }
    
        public static final Object put (String key, Objects value) {
            w.lock();
            try {
                return map.put(key, value);
            } finally {
                w.unlock();
            }
        }
    
        public static final void clear() {
            w.lock();
            try {
                map.clear();
            } finally {
                w.unlock();
            }
        }
    }
    

    上面的这段代码就是使用了读写锁来保证map的线程安全。

    参考:

    1.JAVA并发的艺术
    2.http://www.cnblogs.com/dolphin0520/p/3923167.html
  • 相关阅读:
    dom4j 创建XML文件
    Convert.ToInt32()与int.Parse()的区别
    委托
    工厂模式
    策略模式
    大型网站架构演化
    字符串反转(面试)
    switch(面试)
    带宽计算
    新语法
  • 原文地址:https://www.cnblogs.com/SpeakSoftlyLove/p/5565579.html
Copyright © 2011-2022 走看看