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
原文地址:https://www.cnblogs.com/SpeakSoftlyLove/p/5565579.html