精华内容
下载资源
问答
  • Java锁Lock源码分析(一)

    千次阅读 2018-02-27 15:59:26
    Java中的锁Lock源码分析(一) Java中的锁有很多,同时也是了整个并发包的基础,可以说明白了锁整个并发包你也就能明白一半了,如果之前你有所了解的话java中的锁你或许对这些名词有些概念: 独占锁、共享锁 公平...

    Java中的锁Lock源码分析(一)

    Java中的锁有很多,同时也是了整个并发包的基础,可以说明白了锁整个并发包你也就能明白一半了,如果之前你有所了解的话java中的锁你或许对这些名词有些概念:

    • 独占锁、共享锁
    • 公平锁、非公平锁、重入锁
    • 条件锁
    • 读写锁

    本节要点:

    0)锁是如何表示的(怎么样就代表获取到了锁)
    1)volatile在作用
    2)lock的源码分析
    3)重入锁是如何做到的
    4)公平锁与非公平锁的区别

    我们使用ReentrantLock的方式很简单在方法体内lock.lock();finally中执行lock.unlock()方法,非常简单。
    进入源码可以看到我们常说的AQS(AbstractQueuedSynchronizer)

    lock方法:

        public void lock() {
            sync.lock();
        }
    

    这里写图片描述

    ASQ的成员 state int类型 volatile修饰

        private volatile int state;
    

    这里写图片描述

    CAS(就是在操作AQS的state字段)最终也是调用sun.misc.Unsafe相关的方法,这个方法的四个参数第一个表示操作的是那个对象,第二个表示操作对象字段的偏移量,第三个是期望值,第四个是更新值
    这里写图片描述
    lock方法返回就是获取了锁,即上图CAS设置整个state+1返回true,就说明获取到了锁。

    要点0的答案:AQS的volatile int state +1表示获取到了锁。

    通过cas设置AQS的成员status,大家注意到status是用volatile来修饰的,它在此处表示让所线程能够获取到最新更改的值。

    要点1的答案

    a: 保证变量在线程之间的可见性 就是上面说的
    b:禁止指令重排序 在编译阶段插入内存屏障,来特定禁止指令重排序

    我来先画张图表示下主存中变量和方法栈中的变量关系:
    我们知道对象的成员是跟对象在堆(主存)中,方法运行时在栈中的
    这里写图片描述

    线程在栈中运行方法修改变量的时候会从主存中拷贝一个副本到自己的栈中,当方法修改变量执行返回会把最新值写会到主存。

    1)没有使用volatile修饰时,thread1和thread2同时执行同一个方法来修改state为1(cas的第三个值expcet=0,update=1),那么当thread1返回之后写会到主存,thread2没有感知到还认为是expect=0,update=1 ,thread2中就是老的数据此次cas应该是也会成功,修改了相当于是成功获取到了锁 ,对于独占锁来说肯定是不对的。

    2)使用volatile修饰时,当thread1写会成功之后会让其它线程中该变量的副本失效,并重新从主存load,这样一来thread2 expect=0,update=1就会失败,因为此时的expect=0是不成立的,此时的state已经是1了如下图。
    这里写图片描述

    volatile在此处的就是保证变量被修改的最新值,能够被其它线程感知。

    要点2源码分析

    ReentrantLock改造方法有个参数能决定是否是公平所

     public ReentrantLock(boolean fair) {
         sync = fair ? new FairSync() : new NonfairSync();
     }
    

    公平锁lock方法如下:
    这里写图片描述

    非公平锁lock方法:
    这里写图片描述

    刚开始看的时候我一直感觉不到公平锁和非公平锁到底区别在哪里???

    要点4的答案的第一部分

    公平锁与非公平锁基本一样其实在方法的最外层就可以看到:
    非公平锁先进性一次CAS抢占

    要点4的答案的第二部分
    公平锁先判断队列(双向链表)为空(head==tail)在进行cas抢占
    最终两者为获取所的线程都会进入到队列中,稍后你会看到。

    AQS的模板方法acquire(args)
    它是ReentrantLock成员Sync的整个锁的逻辑,所有的类型的都是基于这个模板方法实现的:
    AQS模板方法acquire

    我们以三个线程thread1,thread2,thread3同时执行lock.lock()方法展开源码的分析,以为例非公平锁:

    lock方法如下:
    这里写图片描述

    thread1,thread2,thread3三个线程同时进入方法,都先进行一次CAS获取锁一下,设置state,expect=0,update=1,
    假设thread1设置成功,那么独占线程设置为当前thread1,获取到了锁lock方法退出,thread1就可以执行业务逻辑了。

    thread2和thread3都会进入else即acquire(1)方法,
    成员Sync提供了整个的锁的逻辑,acquire() 为AQS实现锁逻辑的模板方法
    这里写图片描述

    tryAcquire方法在非公平锁实现中调用了nonfairTryAcquire
    这里写图片描述

    三个线程我们还是一个一个来分析:
    thread1进入acquire(1):
    如果再次调用了lock.lock()那么还是同样会进入到acquire进入到nonfairAcquire(1) 此时getState() 1
    当前线程独占线程 再次将state+1了,此时state thread1此时就表明了重入了,nonfairTryAcquire返回true,tryAcquire返回true,acquire方法退出,lock方法退出,thread1成功的再次获取到锁,state=2了。

    要点3的答案:获取锁的线程,还能在获取锁就表示重入

    thread2进入acquire(1):
    我们假设thread1是持有锁的线程,那么本次的tryAcqurie返回了false。进入到addWaiter(Node.EXCLUSIVE)方法。
    我们先看下Node的结构:

    static final class Node {
            static final Node SHARED = new Node();
            static final Node EXCLUSIVE = null;
            static final int CANCELLED =  1;
            static final int SIGNAL    = -1;
            static final int CONDITION = -2;
            static final int PROPAGATE = -3;
            volatile int waitStatus;
            volatile Node prev;
            volatile Node next;
            volatile Thread thread;
            Node nextWaiter;
            Node() {    // Used to establish initial head or SHARED marker
            }
            Node(Thread thread, Node mode) {     // Used by addWaiter
                this.nextWaiter = mode;
                this.thread = thread;
            }
            Node(Thread thread, int waitStatus) { // Used by Condition
                this.waitStatus = waitStatus;
                this.thread = thread;
            }
        }
    

    预先透漏下这就是一个FIFO的双向链表,这里waiterStatus是进入到链表之后决定是否可以尝试获取锁,每个节点的等待状态的。
    前面的state是尝试获取锁的
    这里的waitStatus是等待链表(队列)中的状态,不要记混了。
    waitStatus有五个值:1表示链表中节点取消,0表示链表中节点初始状态 ,-1表示链表中节点等待唤醒状态,-2表示链表中节点是条件锁(下一篇博文会说),-3表示传播

    addWaiter源码

    这里写图片描述

    这里写图片描述

    构造独占节点进入enq方法,进入死循环中,我们来看下每循环一次都有那些变化。

    下图为addWaiter的一种场景(并不是一定会这样,主要看线程执行到那个方法什么时候入队)就是一个简单的入队操作,入队成功之后就自动返回了当前Node。

    这里写图片描述

    这里画图主要是看waitStatus跟下面的部分结合。

    入队之后然后就是自旋获取锁的部分,代码:
    所谓自旋

    不是一直在执行这段逻辑 head.next 有机会tryAcquire一次,

    成功则获取锁就结束
    失败则跟其它线程一样 修改prev.waitStatus=-1,在tryAcquire一次,如果在失败就自己park住

    这里写图片描述

    哎,又是一个死循环,来看看逻辑是如何的。
    上图的节点入队是跟这里交叉的,也就是说thread2入队的时候,thread3也刚入队,两个线程也可能是同时同时进入acquireQueued的也有可能是thread2进入完了acquireQueued,thread3才刚执行addWaiter,是不确定的,但不论如何最终执行逻辑都是一样的(不管是并行的还是先后的)。

    假设这里是thread2执行,获取node到prev如果为head则再次执行tryAcquire(1)如果获取到的话,thread2的node设置为队列的头结点,thread2获取返回,acquireQueued返回,acquire返回,lock返回,thread2执行业务逻辑。
    如果tryAcquire(1)失败或者不是node.prev!=head(比如thread3的node),进入方法shouldParkAfterFailedAcquire(prevNode,node)
    这里写图片描述
    ws>0的情况其实是取消了节点,图中ws的循环时将取消的节点移除掉。

    这里我们以thread3执行为例(那个都一样),还记得Node.waitStatus的那5个值吗?

    waitStatus有五个值:
    1表示链表中节点取消,
    0表示链表中节点初始状态 ,
    -1表示链表中节点等待唤醒状态,
    -2表示链表中节点是条件锁(下一篇博文会说),
    -3表示传播

    shouldParkAfterFailAcquire是在外层的死循环中if语句中被多次调用的,还是我们在来看看那每轮的结果。

    这里写图片描述

    此时thread2和thread3都LockSupport.park(this)挂起了,阻塞住了,等待thread1唤醒,看看thread1是如何唤醒挂起线程的
    lock.unlock方法的执行逻辑
    这里写图片描述

    就两个部分tryRelease(1)和unparkSuccessor(head),也就是对应了两个操作,释放锁,唤醒下一个等待节点

    释放锁:
    这里写图片描述
    加锁的时候是对state进行加操作,release进行减操作。
    重入几次即state>0,就要释放几次,很简单明了。

    唤醒头结点下一个未取消的节点 upparkSuccessor(head);
    这里写图片描述

    将head.waitStatus设置为0,找到第一个head.next.waitStatus<=0,将其唤醒。

    唤醒了之后还需要从等待队列tryAccquire来抢占,再回到acquireQueued
    这里写图片描述

    此时的等待节点的状态如下:

    这里写图片描述
    ps:head.waitStatus=0和-1都是可能的

    0 t2正在tryAccquire,t1刚释放,成功
    -1 t2tryAcquire失败,将prev.waitStatus=-1,再由t1释放的时候,唤醒t2

    此时thread2的node.prev==head && tryAcquire(1)便能够成功,将thread2设置为设置为head从等待队列中摘除掉。

        private void setHead(Node node) {
            head = node;
            node.thread = null;
            node.prev = null;
        }
    

    thread2的acquireQueued方法返回,acquire方法返回,lock.lock()方法返回,thread2执行业务逻辑。
    此时队列等待状态如下:
    这里写图片描述

    整个流程的闭环就结束了。

    补充:
    上面讲的lock()方法如果当前线程获取不到锁,那么该线程会一直阻塞。实际情况下还有如下需求:

    1)尝试获取锁一次,失败了返回失败,成功就返回成功,不阻塞,只是试一下。
    2)超时尝试,如果尝试获取锁失败了,一直重试,或者等一会再尝试获取锁。

    其实分别对应两个方法:
    tryLock()
    tryLock(timeout,unit)

    tryLock()方法
    尝试一下获取锁

    public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
    }
    final boolean nonfairTryAcquire(int acquires) {
        final Thread current = Thread.currentThread();
        int c = getState();
        if (c == 0) {
            if (compareAndSetState(0, acquires)) {
                setExclusiveOwnerThread(current);
                return true;
            }
        }
        else if (current == getExclusiveOwnerThread()) {
            int nextc = c + acquires;
            if (nextc < 0) // overflow
                throw new Error("Maximum lock count exceeded");
            setState(nextc);
            return true;
        }
        return false;
    }
    

    太简单了(非公平方式)
    state=0(没有线程获取锁)的时候cas一下
    state>0(有线程获取锁)的时候判断是不是自己获取到的锁,是就重入state++

    tryLock(timeout,unit)方法

    public boolean tryLock(long timeout, TimeUnit unit)
            throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }
    public final boolean tryAcquireNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        return tryAcquire(arg) ||
            doAcquireNanos(arg, nanosTimeout);
    }
    private boolean doAcquireNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (nanosTimeout <= 0L)
            return false;
        final long deadline = System.nanoTime() + nanosTimeout;//①
        final Node node = addWaiter(Node.EXCLUSIVE);
        boolean failed = true;
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head && tryAcquire(arg)) {
                    setHead(node);
                    p.next = null; // help GC
                    failed = false;
                    return true;
                }
                nanosTimeout = deadline - System.nanoTime();
                if (nanosTimeout <= 0L)
                    return false;
                if (shouldParkAfterFailedAcquire(p, node) &&
                    nanosTimeout > spinForTimeoutThreshold)
                    LockSupport.parkNanos(this, nanosTimeout);//②
                if (Thread.interrupted())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
    

    逻辑也是很简单:先放入阻塞队列(FIFO双向链表)
    怎么样跟你像的不一样吧不是一直在尝试获取锁而是根据timeout时长来判定
    1)等待时间小于1ms=1000纳秒=spinForTimeoutThreshold=1000L,就无限尝试直至超时
    2)等待时间>1ms 就调用LockSupport.park(timeout),超时后,再次逻辑小于0返回fase,获取锁失败
    最长失败的情况下都会讲改Node从阻塞队列(FIFO双向链表)中移除掉。

    嗯,看来jdk对某个线程阻塞的时间主要靠的LockSupport来支持,最终调用unsafe来调用操作系统的阻塞时间。

    总结:

    ReentrantLock的底层是AQS,通过控制state完成一些锁特有的特性:重入、公平与非公平、读写锁(后面的文章会说明)
    获取锁就是当前线程成功修改了AQS的volatile成员state
    获取锁失败就进入到了AQS的等待队列(FIFO的双向无环链表),进入到等待队列之后开始自旋,当前节点的waitStatus=-1之后lockSupport.park()挂起自己,等待唤醒
    获取锁的线程释放锁(state执行减操作),唤醒head节点之后第一个未取消的等待节点
    head节点之后第一个未取消的等待节点被唤醒,判断prev是否为head 是head则尝试获取所,将自己设置为head节点,将原先老的head移除等待队列。

    展开全文
  • Android多线程研究(9)——线程锁Lock

    万次阅读 多人点赞 2014-06-08 21:08:55
    在前面我们在解决线程同步问题的时候使用了synchronized关键字,今天我们来看看Java 5.0以后提供的线程锁Lock.Lock接口的实现类提供了比使用synchronized关键字更加灵活和广泛的锁定对象操作,而且是以面向对象的...

    在前面我们在解决线程同步问题的时候使用了synchronized关键字,今天我们来看看Java 5.0以后提供的线程锁Lock.


    Lock接口的实现类提供了比使用synchronized关键字更加灵活和广泛的锁定对象操作,而且是以面向对象的方式进行对象加锁。

    		@Override
    		public void run() {
    			while(true){
    				Lock lock = new ReentrantLock();
    				try {
    					lock.lock();
    					Thread.sleep(new Random().nextInt(3000));
    					String data = readData();
    					System.out.print("读取数据: " + data);
    				} catch (InterruptedException e) {
    					e.printStackTrace();
    				}finally{
    					lock.unlock();
    				}
    			}
    		}

    读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,写锁与写锁互斥,这是由JVM控制的。

    import java.util.Random;
    import java.util.concurrent.locks.ReadWriteLock;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    
    public class ReadWriteLockTest {
    	static ReadWriteLock rwl = new ReentrantReadWriteLock();
    	
    	private static String data = null;
    	public static void main(String[] args) {
    		Runnable runnable1 = new MyRunnable1();
    		Runnable runnable2 = new MyRunnable2();
    		for(int i=0; i<3; i++){
    			new Thread(runnable1).start();
    			new Thread(runnable2).start();
    		}
    	}
    	
    	static class MyRunnable1 implements Runnable{
    		
    		@Override
    		public void run() {
    			writeData("" + new Random().nextInt(100));	
    		}
    	}
    	
    	static class MyRunnable2 implements Runnable{
    
    		@Override
    		public void run() {
    			readData();		
    		}
    	}
    	
    	private static void writeData(String var){
    		rwl.writeLock().lock();
    		try {
    			System.out.println(Thread.currentThread().getName() + " 准备写");
    			Thread.sleep(new Random().nextInt(3000));
    			data = var;
    			System.out.println(Thread.currentThread().getName() + " 写完毕");
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}finally{
    			rwl.writeLock().unlock();
    		}
    		
    	}
    	
    	private static void readData(){
    		rwl.readLock().lock();  //用读锁锁住
    		try {
    			System.out.println(Thread.currentThread().getName() + " 准备读");
    			Thread.sleep(new Random().nextInt(3000));
    			System.out.println(Thread.currentThread().getName() + " 读完毕");
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}finally{
    			rwl.readLock().unlock();
    		}
    	}
    }
    

    用过Hibernate框架的朋友可能知道,Hibernate查询数据库有缓存机制,如果某个数据在内存中存在则可以并发的去读取,如果缓存中没有数据则需要互斥的去从数据库取数据。

    import java.util.HashMap;
    import java.util.Map;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    
    public class CacheDemo {
    	private Map<String, Object> cache = new HashMap<String, Object>();
    	public static void main(String[] args) {
    		
    	}
    	
    	private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
    	/**
    	 * 实现多个并发读,互斥的写 	
    	 * @param key
    	 * @return
    	 */
    	public Object getData(String key){
    		rwl.readLock().lock();
    		Object value = null;
    		try{
    			value = cache.get(key);
    			if(value == null){
    				rwl.readLock().unlock();  //释放读锁
    				rwl.writeLock().lock();   //添加写锁
    				try{
    					if(value == null){  //放置其他线程加载数据
    						value = "去数据库查询"; //这里模拟从数据库查询
    						if(value == null){
    							//TODO 抛出异常
    						}
    					}
    				}finally{
    					rwl.writeLock().unlock();
    				}
    				rwl.readLock().lock();  //锁还给读线程
    			}
    		}finally{
    			rwl.readLock().unlock();
    		}
    		return value;
    	}
    }
    
    上面获取数据的大概过程如下:

    1、获取读锁,读取数据

    2、如果有数据则直接返回,并释放读锁让其他线程读。

    3、如果内存中没有数据则从数据库写入内存,释放读锁并添加写锁(这样写入数据就可以达到可以互斥)

    4、读入内存后释放写锁并还回读锁(和后面的unlock()对应)

    5、如果在添加写锁的时候同时有多个线程,则只能有其中一个线程抢到锁,等拥有锁的线程释放写锁后,其他线程就会抢到写锁,但是此时数据已经写入内存,则需要判断内存数据是否为null如果不为null则直接释放写锁。


    展开全文
  • android 线程锁Lock

    千次阅读 2017-09-20 08:41:17
    Lock的使用。 这个其实和SynchronizedClass 是一样的。我记得我的一篇博客写过这个内容。再次记录一下。 一、同步机制关键字synchronized 对于java来说,最常用的同步机制就是synchronized关键字,他是一种...
    今天,简单讲讲android的线程锁
    
    

    Lock的使用。


    这个其实和SynchronizedClass 是一样的。我记得我的一篇博客写过这个内容。再次记录一下。

    一、同步机制关键字synchronized
    对于java来说,最常用的同步机制就是synchronized关键字,他是一种基于语言的粗略锁,能够作用于对象、函数、class。每个对象都只有一个锁,谁能够拿到这个锁谁就有访问权限。当synchronized作用于函数时,实际上锁的也是对象,锁定的对象就是该函数所在类的对象。而synchronized作用于class时则是锁的这个Class类,并非具体对象。

    public class SynchronizedClass {
        public synchronized void syncMethod(){
            //代码
        }
    
        public void syncThis(){
            synchronized (this){
                //代码
            }
        }
    
        public void syncClassMethod(){
            synchronized (SynchronizedClass.class){
                //代码
            }
        }
    
        public synchronized static void syncStaticMethod(){
            //代码
        }
    }
    


    上面演示了同步方法、同步块、同步class对象、同步静态方法。前2种锁的是对象,而后两种锁的是class对象。对于class对象来说,它的作用是防止多个线程同时访问添加了synchronized锁的代码块,而synchronized作用于引用对象是防止其他线程访问同一个对象中synchronized代码块或者函数。


    二、显示锁Lock。

    Lock接口的实现类提供了比使用synchronized关键字更加灵活和广泛的锁定对象操作,而且是以面向对象的方式进行对象加锁。

    public class ReentrantLockDemo {
        Lock lock = new ReentrantLock();
    
        public void doSth(){
            lock.lock();
            try {
                //执行某些操作
            }finally {
                lock.unlock();
            }
        }
    }


    区别:

    需要注意的是,用sychronized修饰的方法或者语句块在代码执行完之后锁自动释放,而是用Lock需要我们手动释放锁,所以为了保证锁最终被释放(发生异常情况),要把互斥区放在try内,释放锁放在finally内!!


    3、读写锁ReadWriteLock


    当我们读取与写入数据时,有这么一个需求:读与写互斥、写与写互斥、读与读不互斥。这里就必须用到读写锁。

    package SychronizedTest;
    
    import java.util.concurrent.locks.ReadWriteLock;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    /**
     * 读写锁测试
     * 
     * @author zy_style
     */
    public class ReadWriteLockTest {
    
    	/**
    	 * @author zhouyang 2016-12-1
    	 * @time 下午3:01:27
    	 * @param args
    	 */
    	public static void main(String[] args) {
    		final Data data = new Data();
    		// 开启3个子线程,分别写入数据
    		for (int i = 0; i < 3; i++) {
    			new Thread() {
    				public void run() {
    					for (int j = 0; j < 5; j++) {
    						try {
    							data.set(j); // 写入数据
    						} catch (Exception e) {
    							e.printStackTrace();
    						}
    					}
    				};
    			}.start();
    		}
    
    		// 分别读取数据
    		for (int i = 0; i < 3; i++) {
    			new Thread() {
    				public void run() {
    					for (int j = 0; j < 5; j++) {
    						try {
    							data.get(); // 读取数据
    						} catch (Exception e) {
    							e.printStackTrace();
    						}
    					}
    				};
    			}.start();
    		}
    	}
    
    }
    
    /**
     * 需要操作的数据
     * 
     * @author zy_style
     */
    class Data {
    	private int data;
    	private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    
    	public void set(int data) throws Exception {
    		readWriteLock.writeLock().lock(); // 获取写锁
    		try {
    			System.out.println(Thread.currentThread().getName() + "准备写入数据...");
    			Thread.sleep(50); // 模拟耗时操作
    			this.data = data;
    			System.out.println(Thread.currentThread().getName() + "写入数据成功!");
    		} finally {
    			readWriteLock.writeLock().unlock(); // 释放写锁
    		}
    
    	}
    
    	public void get() throws Exception {
    		readWriteLock.readLock().lock(); // 获取读锁
    		try {
    			System.out.println(Thread.currentThread().getName() + "准备读取数据...");
    			Thread.sleep(50); // 模拟耗时操作
    			System.out.println(Thread.currentThread().getName() + "读取数据:"
    					+ this.data);
    		} finally {
    			readWriteLock.readLock().unlock(); // 释放读锁
    		}
    
    	}
    }
    



    部分运行结果如下:

    Thread-1准备写入数据...
    Thread-1写入数据成功!
    Thread-2准备写入数据...
    Thread-2写入数据成功!
    Thread-5准备读取数据...
    Thread-3准备读取数据...
    Thread-4准备读取数据...
    Thread-5读取数据:0
    Thread-3读取数据:0
    Thread-4读取数据:0


    可以看到,读与写、写与写确实互斥了,但是读与读没有互斥,这就是ReadWriteLock带来的好处,它在保证共享数据并发操作的完整性和一致性,最重要的是提高了读写的效率~!


    android 线程锁Lock就讲完了。


    就这么简单。

    展开全文
  • swift 互斥锁lock学习

    千次阅读 2016-09-13 14:17:31
    一些学习过程中的难点解决lock锁看了一片文章,写的很牛车:http://blog.csdn.net/hello_hwc/article/details/50037505例子lock锁,我是用于两个线程同时执行一段代码或者一个方法,比如同时刷新auth认证,例如:...

    一些学习过程中的难点解决

    lock锁看了一片文章,写的很牛车:http://blog.csdn.net/hello_hwc/article/details/50037505

    例子

    lock锁,我是用于两个线程同时执行一段代码或者一个方法,比如同时刷新auth认证,例如:

    class ViewController: UIViewController {
        let lock = NSLock()
        var person = Person(name: "Leo", age: 23)
        override func viewDidLoad() {
            super.viewDidLoad()
            let queue1 = dispatch_queue_create("com.test.queue1", DISPATCH_QUEUE_SERIAL)
            let queue2 = dispatch_queue_create("com.test.queue1", DISPATCH_QUEUE_SERIAL)
            dispatch_async(queue1) { () -> Void in
                self.lock.lock()
                self.person.update("queue1", delay: 2, age: 1)
                self.lock.unlock()
            }
            dispatch_async(queue2) { () -> Void in
                self.lock.lock()
                self.person.update("queue2", delay: 1, age: 2)
                self.lock.unlock()
            }
            self.performSelector("logPerson", withObject: nil, afterDelay: 4)
            // Do any additional setup after loading the view, typically from a nib.
        }
        func logPerson(){
            NSLog("%@ %d", person.name,person.age)
        }
    
    }

    这样就会当执行 self.person.update(“queue2”, delay: 1, age: 2)时候锁定,执行完后释放锁,然后下一个线程才会重新调用update,这样数据不会错乱

    我的代码是这样的:

     case .Failure(let error):
          if response.response?.statusCode == 401{//刷新token
          dispatch_async(queue3) { () -> Void in
             lock?.lock()//这里添加互斥锁,防止一起刷新token,这样就会分开之行token方法cjq
            RefreshToken({ (AnyObject) in
                lock?.unlock()
                var hs = headers
                hs!["Authorization"] = NSUserDefaults.standardUserDefaults().stringForKey("access_token")
            }
         }, logOut: { (NSError) in
                  logOut?()
                  lock?.unlock()
                  })
          }
     }else{
        failure?(error)
            }
      }
    

    RefreshToken(success:((AnyObject?) -> Void)?, logOut:((NSError?) -> Void))是闭包函数

    展开全文
  • 在Java5中,专门提供了对象,利用可以方便的实现资源的封锁,用来控制对竞争资源并发访问的控制,这些内容主要集中在java.util.concurrent.locks 包下面,里面有三个重要的接口Condition、Lock、ReadWriteLock。...
  • (Lock)的概述 线程安全问题是因为多个线程并发访问共享数据。于是很容易我们就想到将多个线程对共享数据的访问转换为串行访问。同一时刻只能有一个线程来访问共享数据。就是利用这种思路来保障线程安全的一种...
  • python原语--锁Lock

    千次阅读 2018-10-27 11:11:11
    python多进程,多线程之机制 添加的原因: ...lock = Lock() 对象一旦创建,就可以随时被进程或者线程调用,并且一次创建只有一把,如果多个资源想同时获取,必须‘排队’,等上一个进程/线...
  • 线程同步Synchronized,监视器monitor和锁lock的关系 既然有关监视器monitor的概念比较难,大家怎么解释的都有。首先我给出一下java的官方文档,也是最权威的解释: Synchronization is built around an internal ...
  • 默认情况下 当进程执行if语句里面lock.acquire()失败时不会跳出if,而是一直等待的释放 所以你可以写成 if _from.lock.acquire(False): 不阻塞 从而跳出 Lock.acquire([ blocking ] ) 获取锁定,阻止或不阻止...
  • C# 关于线程锁lock的使用方法

    万次阅读 多人点赞 2016-09-02 10:07:05
    在某些情况下,我们希望A中的代码块(B)同步的执行,即同一时刻只有一个线程执行代码块B,这就需要用到lock)。lock 关键字可以用来确保代码块完成运行,而不会被其他线程中断。它可以把一段代码定义为互斥段...
  • 自解锁lock_guard

    千次阅读 2017-06-22 14:42:53
    今天遇到lock_guard,大概学习了一下,先贴出源码。 // LOCKS template class lock_guard { // class with destructor that unlocks mutex public: typedef _Mutex mutex_type; explicit lock_guard(_...
  • python里协程使用同步锁Lock

    千次阅读 2017-09-09 11:04:43
    比如asyncio就定义了一个对象Lock,它一次只允许一个协程来访问共享的资源,如果多协程想访问就会阻塞起来,也就是说如果一个协程没有释放这个,别的协程是没有办法访问共享的资源。例子:import a
  • oracle 查询并清除锁lock

    千次阅读 2017-11-15 15:21:30
    oracle在做表数据更新时, 会产生相应的.  一般在使用第三方数据库工具在进行更新时, 由于各种原因操作中断, 会造成表的. 这时候一般需要手工清除 1. 查询oracle(常用) SELECT SESS.SID, SESS....
  • Java中的机制及Lock的释放-获取建立的happens before 关系 是java并发编程中最重要的同步机制。除了让临界区互斥执行外,还可以让释放的线程向获取同一个的线程发送消息。 下面是释放-获取的...
  • lock-spring-boot-starter是一个基于Spring Boot的starter机制编写的分布式工具。 与其他分布式不同的是,使用起来更方便快捷,只需要通过注解@Lock的方式即可实现对方法进行加锁。 官网地址:...
  • AQS中的ReentrantLock.lock可以对应理解成synchronized刚进入代码块获取到 AQS中的ReentrantLock.unlock可以对应理解成synchronized代码块结束释放 Condition condition = reentrantLock.newCondition() ...
  • 因为当调用Synchronized修饰的代码时,并不需要显示的加锁和解锁的过程,所以称之为隐式。Sychronized的用法:1、同步方法体,在方法声明中使用,如下:public synchronized void method(){
  • 因为synchronized 是关键字,无法看到源代码,所以只能做一个简单的分析对比了, ...locklock能做synchronized能做的所有的事情,但是lock 能过在资源竞争地方,通过投票等方法让其他释放。而sync
  • 本文只针对C#中,多线程同步所用到的(lock)作为研究对象。由于想更直观的显示结果,所以,在做demo的时候,就把多线程通过事件操作UI的代码也写了出来,留作备忘和分享吧。   其实多线程的同步,使用同步...
  • SAP SM12 解锁Lock Table

    千次阅读 2013-06-18 10:32:24
    出现这种情况,都可以通过T-code... 遇到这种情况,我们首先要判断被LOCK的记录是否正被处理,如果没有就可以直接删除;如果有那只能等相关操作完成自动释放,或者通知相关使用人退出相关操作,也可以释放。    1
  • c# 同步进程 lock千万别乱用

    千次阅读 2018-05-24 10:59:02
    因为我使用的是多线程 list在满足条件下进行add,会在两分钟后被remove掉,所以 我使用了进程 刚开始是这样的 if(p.contains(a)) { lock{ p.add(a); } } else  。。。 后来老是出现数据在某个时刻老是重复 而且...
  • 锁Lock与原子变量Atomic的性能比较

    千次阅读 2018-06-19 08:05:33
    在中低程度的竞争下,原子变量能提供更高的可伸缩性(在发生竞争时会挂起线程,从而降低了CPU的使用率和共享内存总线上的同步通信量),而在高强度的竞争下,能够更有效地避免竞争。 在单CPU的系统上,基于...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 444,663
精华内容 177,865
关键字:

锁lock