Java 公平锁/非公平锁/可重入锁/递归锁/自旋锁/独占锁(写锁)/共享锁(读锁)/互斥锁 代码实现

目录

公平锁/非公平锁

两者区别

可重入锁(也叫递归锁)

理论知识

实例(synchronized)

实例(ReentrantLock)

自旋锁

 实例

独占锁(写锁)/共享锁(读锁)/互斥锁


公平锁/非公平锁

公平锁:是指多个线程按照申请锁的顺序来获取锁,类似于排队打饭,先来后到

非公平锁:是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁,在高并发的情况下,有可能会造成优先级反转或者饥饿现象

两者区别

公平锁:就是很公平,在并发环境下,每个线程在获取锁时会先查看此锁维护的等待队列,如果为空,或者当前线程是等待队列的第一个,就占有锁,否则会加入到等待队列中,以后会按照FIFO的规则从队列中取到自己

 非公平锁:比较粗鲁,上来就直接尝试占有锁,如果尝试失败,就采用类似公平锁那种方式。

非公平锁的优点在于吞吐量比公平锁大

 

并发包中ReentrantLock的创建可以指定构造函数的boolean类型来得到公平锁,默认是非公平锁,

 对于Synchronized而言,也是一种非公平锁

可重入锁(也叫递归锁)

 

理论知识

指同一个线程外层函数获得锁之后,内层递归函数任然能获取该锁的代码,在同一个线程的外层方法获取锁的时候,在进入内层方法会自动获取锁。也就是说,线程可以进入任何一个它已经拥有的锁所同步着的代码块

Java 公平锁/非公平锁/可重入锁/递归锁/自旋锁/独占锁(写锁)/共享锁(读锁)/互斥锁 代码实现_第1张图片

实例(synchronized)

public class Phone {

    public synchronized void sendSMS() throws Exception
    {

        System.out.println(Thread.currentThread().getName()+" invoked send SMS");
        sendEmail();
    }


    public synchronized void sendEmail() throws Exception
    {
           //睡五秒
        Thread.sleep(5000);
        System.out.println(Thread.currentThread().getName()+" invoked send Email");
    }

    public static void main(String [] args){

        Phone phone = new Phone();
        new Thread(()->{

            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"t2").start();

        new Thread(()->{

            try {
                phone.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"t1").start();



    }
}

停顿5s 
t2 invoked send Email

t1 invoked send SMS 
停頓5s

t1 invoked send Email

实例(ReentrantLock)

public class Phone {

   Lock lock= new ReentrantLock();

    public  void sendSMS() throws Exception
    {
        try{
            lock.lock();
            System.out.println(Thread.currentThread().getName()+" invoked send SMS");
            sendEmail();
            }catch(Exception e){
             e.getMessage();
            }
        finally {

                lock.unlock();
        }

    }


    public  void sendEmail() throws Exception
    {

        try{
            lock.lock();
            Thread.sleep(5000);
            System.out.println(Thread.currentThread().getName()+" invoked send Email");
        }catch(Exception e){
            e.getMessage();
        }
        finally {

            lock.unlock();
        }

        //睡五秒

    }

    public static void main(String [] args){

        Phone phone = new Phone();
        new Thread(()->{

            try {
                phone.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"t2").start();

        new Thread(()->{

            try {
                phone.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        },"t1").start();



    }
}

停顿5s 
t2 invoked send Email

t1 invoked send SMS 
停頓5s

t1 invoked send Email

自旋锁

Unsafe类加上CAS思想就是自旋锁

 自旋锁是指尝试获取锁的线程不会立即阻塞,而是采用循环的方式尝试获取锁这样的好处在于减少线程上下文切换的消耗,缺点是循环会消耗CPU

Java 公平锁/非公平锁/可重入锁/递归锁/自旋锁/独占锁(写锁)/共享锁(读锁)/互斥锁 代码实现_第2张图片

 实例

public class SpinLockDemo {


    AtomicReference atomicReference=new AtomicReference<>();


    public  void myLock(){
        Thread thread= Thread.currentThread();

        System.out.println(Thread.currentThread().getName()+ "  "+ thread.toString()+" come in 000000");

        while(!atomicReference.compareAndSet(null,thread)){

        }
        System.out.println(Thread.currentThread().getName()+ "  "+ thread.toString()+" get lock 000000");
    }

    public  void myUnLock(){
        Thread thread= Thread.currentThread();
        atomicReference.compareAndSet(thread,null);
        System.out.println(Thread.currentThread().getName()+ "  "+ thread.toString()+ " invoke myUnLock");
    }
    
    
    public static void main(String [] args){
        SpinLockDemo spinLockDemo = new SpinLockDemo();
           new Thread(()->{
               spinLockDemo.myLock();
               try {
                   TimeUnit.SECONDS.sleep(5);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
               spinLockDemo.myUnLock();
           },"AA").start();

           //保证AA线程先启动
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        new Thread(()->{
            spinLockDemo.myLock();
            spinLockDemo.myUnLock();
        },"BB").start();

    }
}

AA  Thread[AA,5,main] come in 000000
AA  Thread[AA,5,main] get lock 000000
BB  Thread[BB,5,main] come in 000000
AA  Thread[AA,5,main] invoke myUnLock
BB  Thread[BB,5,main] get lock 000000
BB  Thread[BB,5,main] invoke myUnLock

独占锁(写锁)/共享锁(读锁)/互斥锁

独占锁:指该锁一次只能被一个线程持有,对ReentrantLock和Synchronized 而言都是独占锁
共享锁:指该锁可以被多个线程所持有。

对ReentrantReadWriteLock 其读锁是共享锁,其写锁是独占锁。
读锁的共享锁可以保证并发读是非常高效的,读写,写写,写读的过程都是互斥的。

Before

 

/**
 * Tips:
 *
 * @author Liuq
 * @version 2019年10月21日
 */
public class ReadWriteLockDemo {

     public static void main(String [] args){
         MyCache myCache = new MyCache();

         for(int i = 0; i < 5; i++) {
                final int tempInt=i;

                   new Thread(()->{

                              myCache.put(tempInt+ " ",tempInt+ " ");
                           },String.valueOf(i)).start();
         }

         for(int i = 0; i < 5; i++) {
             final int tempInt=i;

             new Thread(()->{

                 myCache.get(tempInt+ " ");
             },String.valueOf(i)).start();
         }
     }
}

class MyCache{

    private volatile Map map=new HashMap<>();

    public void put(String key ,Object  value){
           System.out.println(Thread.currentThread().getName() +"  正在写入:"+key);

        try {
            TimeUnit.MILLISECONDS.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        map.put(key,value);
        System.out.println(Thread.currentThread().getName() +"  写入完成");
    }


    public void get(String key){
        System.out.println(Thread.currentThread().getName() +"  正在读取:"+key);

        try {
            TimeUnit.MILLISECONDS.sleep(300);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Object o = map.get(key);
        System.out.println(Thread.currentThread().getName() +"  读取完成:"+o);
    }
}

 

Java 公平锁/非公平锁/可重入锁/递归锁/自旋锁/独占锁(写锁)/共享锁(读锁)/互斥锁 代码实现_第3张图片

After



import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * Tips:
 *
 * @author Liuq
 * @version 2019年10月21日
 */
public class ReadWriteLockDemo {

     public static void main(String [] args){
         MyCache myCache = new MyCache();

         for(int i = 0; i < 5; i++) {
                final int tempInt=i;

                   new Thread(()->{

                              myCache.put(tempInt+ " ",tempInt+ " ");
                           },String.valueOf(i)).start();
         }

         for(int i = 0; i < 5; i++) {
             final int tempInt=i;

             new Thread(()->{

                 myCache.get(tempInt+ " ");
             },String.valueOf(i)).start();
         }
     }
}

class MyCache{

    private ReentrantReadWriteLock rwLock=new ReentrantReadWriteLock();


    private volatile Map map=new HashMap<>();

    public void put(String key ,Object  value){
        rwLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() +"  正在写入:"+key);
            TimeUnit.MILLISECONDS.sleep(300);
            map.put(key,value);
            System.out.println(Thread.currentThread().getName() +"  写入完成");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {

            rwLock.writeLock().unlock();
        }

    }


    public void get(String key){
        rwLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() +"  正在读取:"+key);

            TimeUnit.MILLISECONDS.sleep(300);

            Object o = map.get(key);
            System.out.println(Thread.currentThread().getName() +"  读取完成:"+o);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            rwLock.readLock().unlock();
        }

    }
}

 Java 公平锁/非公平锁/可重入锁/递归锁/自旋锁/独占锁(写锁)/共享锁(读锁)/互斥锁 代码实现_第4张图片

 如果读写线程换一个位子就是这样的结果

public static void main(String [] args){
         MyCache myCache = new MyCache();

         for(int i = 0; i < 5; i++) {
             final int tempInt=i;

             new Thread(()->{

                 myCache.get(tempInt+ " ");
             },String.valueOf(i)).start();
         }

         for(int i = 0; i < 5; i++) {
                final int tempInt=i;

                   new Thread(()->{

                              myCache.put(tempInt+ " ",tempInt+ " ");
                           },String.valueOf(i)).start();
         }

     }

Java 公平锁/非公平锁/可重入锁/递归锁/自旋锁/独占锁(写锁)/共享锁(读锁)/互斥锁 代码实现_第5张图片

你可能感兴趣的:(锁,多线程)