• 锁和多线程:5种锁介绍(三)


     

     

    搞明白 线程 多线程系列

    1.重入锁

    在类中有 synchronized 方法A 和 synchronized 方法B,并在A中调用B,就形成了重入锁.获得A的对象锁,可以直接调用B,并不需要重新请求锁权限.

    package thread;
    
    /**
     * @Author lyf
     * @Date 2018/11/18 0018 14:30
     */
    public class RepeatLock {
      
      public synchronized void A(){
        System.out.println("进入A...");
        B();
      }
      
      public synchronized void B(){
        System.out.println("进入B...");
      }
      
      public static void main(String[] args){
        RepeatLock repeatLock = new RepeatLock();
        for (int i = 0; i < 5; i++) {
          new Thread(()->{repeatLock.A();}).start();
        }
      }
    }
    

     


     

     

    2.中断锁

    使用synchronized修饰的方法,在阻塞状态blocked时不能被外部打断,除非jvm报错.
    使用ReentrantLock中的lockInterruptibly()处于阻塞状态时, 可以被打断.

    package thread;
    
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * @Author lyf
     * @Date 2018/11/18 0018 14:47
     */
    public class InterruptLock {
    
      private ReentrantLock lock = new ReentrantLock();
    
      public synchronized void A() {
           try {
        System.out.println(Thread.currentThread().getName() + "获取锁...");
          while (true) {
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + "执行...");
          }
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    
      public static void main(String[] args) throws InterruptedException {
        
        InterruptLock lock1 = new InterruptLock();
        Thread t1 = new Thread(()->{lock1.A();});
        t1.start();
        Thread t2 = new Thread(()->{lock1.A();});
        t2.start();
        Thread.sleep(2000);
        System.out.println(t1.getName() + ": "+t1.getState());// RUNNABLE 正在运行
        System.out.println(t2.getName() + ": "+t2.getState());// BLOCKED 阻塞状态
        Thread.sleep(1000);
        t2.interrupt();// 打断t2线程
        System.out.println(t2.getName() + ": "+t2.getState());// 依然处于BLOCKED 阻塞状态
      }
    }
    

     


     

    线程0获取锁后, 线程1进入阻塞等待状态.对线程1调用interrupt()打断线程,发现没什么用!线程1还是在等待.

     

    package thread;
    
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * @Author lyf
     * @Date 2018/11/18 0018 14:47
     */
    public class InterruptLock {
    
      private ReentrantLock lock = new ReentrantLock();
    
    
      public void B() {
        try {
          lock.lockInterruptibly();
          System.out.println(Thread.currentThread().getName() + "获取锁...");
          while (true) {
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + "执行...");
          }
        } catch (InterruptedException e) {
          System.out.println(Thread.currentThread().getName() + "被打断...");
        } finally {
          lock.unlock();
        }
      }
    
      public static void main(String[] args) throws InterruptedException {
        
        InterruptLock lock2 = new InterruptLock();
        Thread t1 = new Thread(() -> { lock2.B(); });
        t1.start();
        Thread t2 = new Thread(() -> { lock2.B(); });
        t2.start();
        Thread.sleep(2000);
        System.out.println(t1.getName() + ": "+t1.getState());// RUNNABLE 正在运行
        System.out.println(t2.getName() + ": "+t2.getState());// WAITING 等待状态
        Thread.sleep(1000);
        t2.interrupt();// 打断t2线程
        System.out.println(t2.getName() + ": "+t2.getState());// WAITING 状态(线程延时)
      }
    }
    

     


     

    很明显线程1被打断...

     

    3.公平锁

    当多个线程处于阻塞状态时,由系统随机调度其中一个线程继续执行,无法保证公平性.有可能某个线程永远无法执行.ReentrantLock(true)可以创建公平锁,保证每个阻塞的线程都可以被执行到.

    首先,来看非公平锁的情况,使用new ReentrantLock()创建:

    package thread;
    
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * @Author lyf
     * @Date 2018/11/18 0018 18:46
     */
    public class FairLock {
    
      private ReentrantLock lock = new ReentrantLock();
    
      public synchronized void A() {
        lock.lock();
        System.out.println(Thread.currentThread().getName() + "获得锁...");
        try {
          Thread.sleep(5000);
          System.out.println(Thread.currentThread().getName() + "执行...");
        } catch (InterruptedException e) {
          e.printStackTrace();
        } finally {
          lock.unlock();
        }
      }
    
      public static void main(String[] args) throws InterruptedException {
        FairLock fairLock = new FairLock();
        new Thread(() -> {
          fairLock.A();
        }).start();// 启动线程获得锁
    
        for (int i = 0; i < 5; i++) {
          new Thread(() -> {
            System.out.println(Thread.currentThread().getName() + "等待获得锁...");
            fairLock.A();
          }).start();
        }
      }
    }
    

     


     

    线程0获得锁,线程 4 3 5 2 1 依次进入等待状态,在线程0执行完后,随机选择一个线程执行.

     

    使用new ReentrantLock(true)创建公平锁

    private ReentrantLock lock = new ReentrantLock(true);
    

     


     

    线程0获得锁,线程 1 2 5 4 3 依次进入等待状态,在线程0执行完后,按照顺序 3 4 5 2 1 执行.

     

    4.读写锁

    多个线程执行读操作时,互不影响.但是读写互斥,写写互斥.

    package thread;
    
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    /**
     * @Author lyf
     * @Date 2018/11/18 0018 10:30
     */
    public class MyReadWriteLock {
    
      private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
      private int num = 0;
    
      public void readFile() {
        rwl.readLock().lock();
        try {
          System.out.println(Thread.currentThread().getName() + "执行读操作...");
          Thread.sleep((long) (Math.random() * 1000));
          System.out.println(Thread.currentThread().getName() + "读操作完成...");
        } catch (InterruptedException e) {
          e.printStackTrace();
        } finally {
          rwl.readLock().unlock();
        }
      }
    
    
      public void writeFile() {
        rwl.writeLock().lock();
        System.out.println(Thread.currentThread().getName() + "执行写操作...");
        try {
          num++;
          Thread.sleep((long) (Math.random() * 1000));
          System.out.println(Thread.currentThread().getName() + "写操作完成...num: " + num);
        } catch (InterruptedException e) {
          e.printStackTrace();
        } finally {
          rwl.writeLock().unlock();
        }
    
      }
    
      public static void main(String[] args) {
    
        MyReadWriteLock myReadWriteLock = new MyReadWriteLock();
        for (int i = 0; i < 5; i++) {
          new Thread(()->{myReadWriteLock.readFile();}).start();// 读语句1
          new Thread(()->{myReadWriteLock.readFile();}).start();// 读语句2
          new Thread(() -> { myReadWriteLock.writeFile(); }).start();// 写语句
        }
      }
    }
    

     


     

     

    • 线程0 1 3读操作同时开始,与线程5写操作互斥
    • 线程5写操作与线程2写操作互斥

    5.自旋锁

    多线程下会造成线程处于阻塞状态,不能执行其他操作.自旋锁是一种非阻塞锁,允许线程等待期间执行其他操作,直到获得锁.

    package thread;
    
    import java.util.concurrent.atomic.AtomicReference;
    
    /**
     * @Author lyf
     * @Date 2018/11/18 0018 20:23
     */
    public class SpinLock {
      // CAS操作
      AtomicReference<Thread> runThread = new AtomicReference<>();
    
      public void lock() {
        Thread cur = Thread.currentThread();// 获取当前线程
        // 如果需要运行线程标志为null,也就是说现在没有线程在执行,就执行当前线程
        // 如果需要运行线程标志不为null,说明现在有线程在执行,就自己个儿执行自己的
        while (!runThread.compareAndSet(null, cur)) {
          try {
            Thread.sleep(500);
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
          System.out.println(Thread.currentThread().getName() + "在自旋中...");
        }
        try {
          System.out.println(Thread.currentThread().getName() + "开始执行...");
          Thread.sleep(2000);
          System.out.println(Thread.currentThread().getName() + "执行完毕...");
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
    
      public void unlock() {
        Thread cur = Thread.currentThread();
        runThread.compareAndSet(cur, null);
      }
      
      public static void main(String[] args) {
          SpinLock spinLock = new SpinLock();
          Thread t1 = new Thread(()->{
            spinLock.lock();
            try {
              Thread.sleep(2048);
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
            spinLock.unlock();
          });
          Thread t2 = new Thread(()->spinLock.lock());
          t1.start();
          t2.start();
      }
    }
    

     


     

     

    参考资料

  • 相关阅读:
    python开发--信息处理系统
    oracle--表空间操作
    oracle--表空间基本操作
    CPU、内存、磁盘的瓶颈(转载文)
    在pycharm中进行ORM操作
    contenttypes组件 (处理大量外键)
    Django Rest Framework 请求流程
    Python标准库--UUID
    Django REST framework基础:版本、认证、权限、限制
    Django Rest Framework 视图和路由
  • 原文地址:https://www.cnblogs.com/linyufeng/p/9992384.html
Copyright © 2020-2023  润新知