java 记一次synchronized的错误使用 LockUtil工具类

代码如下,

import java.util.HashSet;
import java.util.Set;

public class LockTest1 {

	public static Set<String> map = new HashSet<String>();
	
	public static void testlock(String uid,String prefix) {
		boolean flag = false;
		try {
			if(flag=getLock(uid, prefix)) {
				Thread.sleep(2000);
				System.out.println(Thread.currentThread().getName()+" getLock success");
			} else {
				System.out.println(Thread.currentThread().getName()+" not getLock");
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if(flag)removeLock(uid, prefix);
		}
	}
	public static void testlock2(String uid,String prefix) {
		try {
			if(getLock(uid, prefix)) {
				Thread.sleep(2000);
				System.out.println(Thread.currentThread().getName()+" getLock success");
			} else {
				System.out.println(Thread.currentThread().getName()+" not getLock");
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			removeLock(uid, prefix);
		}
	}
	
	public static boolean getLock(String uid,String prefix){
		String key = uid + prefix;
		synchronized(key.intern()){
			if(map.contains(key)){
				return false;
			} else {
				System.out.println(Thread.currentThread().getName()+" getLocking...");
				map.add(key);
				return true;
			}
		}
	}
	
	public static void removeLock(String uid,String prefix){
		String key = uid + prefix;
		synchronized(key.intern()){
			System.out.println(Thread.currentThread().getName()+" removeLocking...");
			map.remove(key);
		}
	}
	
	public static void main(String[] args) {
		for(int i=0;i<20;i++) {
			new Thread() {

				@Override
				public void run() {
					testlock2("uid-a", "prefix_a");
					//testlock("uid-a", "prefix_a");
				}
				
			}.start();
		}
		try {
			Thread.sleep(10000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

  

运行结果,

Thread-0 getLocking...
Thread-3 not getLock
Thread-2 not getLock
Thread-4 not getLock
Thread-3 removeLocking...
Thread-6 getLocking...
Thread-7 not getLock
Thread-7 removeLocking...
Thread-8 getLocking...
Thread-1 not getLock
Thread-4 removeLocking...
Thread-2 removeLocking...
Thread-11 not getLock
Thread-18 getLocking...
Thread-15 not getLock
Thread-15 removeLocking...
Thread-16 getLocking...
Thread-19 not getLock
Thread-19 removeLocking...
Thread-1 removeLocking...
Thread-14 getLocking...
Thread-10 not getLock
Thread-10 removeLocking...
Thread-12 getLocking...
Thread-5 not getLock
Thread-11 removeLocking...
Thread-9 getLocking...
Thread-5 removeLocking...
Thread-13 getLocking...
Thread-17 not getLock
Thread-17 removeLocking...
Thread-0 getLock success
Thread-12 getLock success
Thread-16 getLock success
Thread-8 getLock success
Thread-14 getLock success
Thread-18 getLock success
Thread-6 getLock success
Thread-0 removeLocking...
Thread-6 removeLocking...
Thread-18 removeLocking...
Thread-14 removeLocking...
Thread-12 removeLocking...
Thread-8 removeLocking...
Thread-16 removeLocking...
Thread-9 getLock success
Thread-9 removeLocking...
Thread-13 getLock success
Thread-13 removeLocking...

根据结果,分析not getLock的线程也调用了removeLocking,所以这里不正确,修改为调用testlock方法,

结果如下,

Thread-0 getLocking...
Thread-4 not getLock
Thread-3 not getLock
Thread-6 not getLock
Thread-2 not getLock
Thread-1 not getLock
Thread-7 not getLock
Thread-10 not getLock
Thread-11 not getLock
Thread-9 not getLock
Thread-5 not getLock
Thread-15 not getLock
Thread-18 not getLock
Thread-19 not getLock
Thread-14 not getLock
Thread-13 not getLock
Thread-17 not getLock
Thread-8 not getLock
Thread-12 not getLock
Thread-16 not getLock
Thread-0 getLock success
Thread-0 removeLocking...

结果正确,解决问题,

另外还可以使用ReentrantLock也可以实现同样的效果,代码如下,

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

public class LockTest2 {

    static int size = 32;
    static List<ReentrantLock> locks = new ArrayList<ReentrantLock>(size);
    static {
        for(int i=0;i<size;i++) {
            locks.add(new ReentrantLock());
        }
    }
    
    public static boolean getLock(String uid,String prefix){
        String key = uid + prefix;
        ReentrantLock lock = locks.get(Math.abs(key.hashCode())%size);
        return lock.tryLock();
    }
    
    public static void removeLock(String uid,String prefix){
        String key = uid + prefix;
        ReentrantLock lock = locks.get(Math.abs(key.hashCode())%size);
        if(lock.isHeldByCurrentThread()) {
            lock.unlock();
        }
    }
    
    public static void testlock(String uid,String prefix) {
        try {
            if(getLock(uid, prefix)) {
                Thread.sleep(2000);
                System.out.println(Thread.currentThread().getName()+" getLock success");
            } else {
                System.out.println(Thread.currentThread().getName()+" not getLock");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            removeLock(uid, prefix);
        }
    }
    
    public static void main(String[] args) {
        for(int i=0;i<20;i++) {
            new Thread() {

                @Override
                public void run() {
                    testlock("uid-a", "prefix_a");
                }
                
            }.start();
        }
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

运行结果如下,

Thread-2 not getLock
Thread-4 not getLock
Thread-0 not getLock
Thread-3 not getLock
Thread-6 not getLock
Thread-5 not getLock
Thread-7 not getLock
Thread-8 not getLock
Thread-10 not getLock
Thread-11 not getLock
Thread-9 not getLock
Thread-12 not getLock
Thread-14 not getLock
Thread-15 not getLock
Thread-16 not getLock
Thread-13 not getLock
Thread-17 not getLock
Thread-18 not getLock
Thread-19 not getLock
Thread-1 getLock success

效果一样,其中

lock.isHeldByCurrentThread()代码就相当于方法一中的 flag=getLock(uid, prefix) ,if(flag)removeLock(uid, prefix); 这个判断
原文地址:https://www.cnblogs.com/xiongjinpeng/p/12911663.html