JAVA锁---------------------Ticket自旋锁

    参考:http://ifeve.com/java_lock_see2/

一:ticket自旋锁

  1. 上节讲了自选锁,自旋锁中常用的有三类,TicketLock ,CLHlock 和MCSlock,本节主要谈谈ticket自旋锁
  2. 概念:ticket锁也是自旋锁的一种,只是它是一种能保证顺序的自选锁,是公平锁
  3. 实现:
    package com.eden.coreLearn.thread.lock;
    
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.atomic.AtomicInteger;
    
    import org.junit.Test;
    
    /**
     * 排队自旋锁,公平锁
     * 
     * @author [email protected] 2016年7月14日 下午12:16:06
     */
    public class TicketSpinLock {
    
        //当期线程能占用的锁的序号
        private AtomicInteger ticketNum = new AtomicInteger(0);
    
        //锁的序号
        private AtomicInteger owner     = new AtomicInteger(0);
    
        //当前线程持有的票据
        private static final ThreadLocal myTicketLocal = new ThreadLocal();
    
        public void lock() {
            int myTicket = ticketNum.getAndIncrement();//票据
            myTicketLocal.set(myTicket);
            while (myTicket != owner.get()) {
    
            }
        }
    
        public void unlock() {
            int myTicket = myTicketLocal.get();
            owner.compareAndSet(myTicket, myTicket + 1);
        }
    
        @Test
        public void testAdd() throws InterruptedException {
            AddClass ac = new AddClass(new TicketSpinLock());
            for (int i = 0; i < 100; i++) {
                new Thread(new AddClassThread(ac), i + "").start();
            }
            TimeUnit.SECONDS.sleep(20);
        }
    
        public class AddClassThread extends Thread {
    
            private AddClass addClass;
    
            public AddClassThread(AddClass addClass) {
                this.addClass = addClass;
            }
    
            @Override
            public void run() {
                addClass.add();
                //            addClass.add2();
            }
        }
    
        public class AddClass {
            private int            i;
    
            private TicketSpinLock ticketLock;
    
            public AddClass() {
            }
    
            public AddClass(TicketSpinLock ticketLock) {
                this.ticketLock = ticketLock;
            }
            public void add() {
                i = i + 1;
                System.out.println(String.format("i=%s", i));
            }
    
            public void add2() {
                ticketLock.lock();
                i = i + 1;
                System.out.println(String.format("i=%s", i));
                ticketLock.unlock();
            }
        }
    }
    

  4. 如上,主要通过三个变量实现ticket自选锁,ticketNum->表示想要占用的锁的序号,owner->表示当前锁的序号,myTicketLocal->记录每个线程想要持有的锁的序号,是ticketNum的线程备份;
  5. 第一个线程进来时,首先领一个号ticketNum,同时告诉这个号我已经领了,下个号(ticketNum)要+1;然后将自己的ticketNum存到自己的线程栈里,然后比较自己领的号是不是和当前锁的序号是一样的,如果一样获得锁,不一样等待锁,这个就是lock函数的过程
  6. 当一个线程释放锁时,首先取出当前自己占用锁的序号与当前正在被占用的锁的序号相比,如果相同,表是当前锁已经被使用,下一个锁应该要+1了,即owner+1
  7. 其实上述过程就相当于我们去银行办业务,然后在取票机取票排队等候是一样的,一个个人就是每个线程,而票号就是ticketNum,柜台显示器上显示的号码就是owner,只有票号ticketNum和柜台显示器上的号码owner相同时,你才能去柜台上办自己的业务,myTicketLocal变量的存在是因为在程序里ticketNum没有一个线程就会+1,所以我们必须将自己的ticketNum备份下来,这样才能在释放锁的时候与owner做比较
  8. 优缺点基本上也就是上节中提到的自旋锁的优缺点

你可能感兴趣的:(多线程,java基础)