zoukankan      html  css  js  c++  java
  • 锁和多线程:3种锁的使用(二)

     

     

    搞明白 线程 多线程系列

    1.synchronized锁

    锁分为 类锁对象锁, 方法锁和私有锁都属于对象锁

    1. 类锁:在代码中的方法上加了staticsynchronized的锁,或者内部使用synchronized(xxx.class)

    2. 对象锁:在代码中的方法上加了synchronized的锁,或者内部使用synchronized(this)的代码段

    3. 私有锁:在类内部声明一个私有属性如private Object lock,在需要加锁的代码段synchronized(lock)

    package com.lyf.lock;
    
    /**
     * @Author lyf
     * @Date 2018/11/17 0017 14:13
     */
    public class Ticket {
      private static int num = 10;
      private Object lock = new Object();
    
      // 类锁 static synchronized
      public static synchronized void buy01() {
        buy();
      }
    
      // 类锁 synchronized (xxx.class)
      public void buy02() {
        synchronized (MyLock.class){
          buy();
        }
      }
    
      // 对象锁 synchronized
      public synchronized void buy03() {
        buy();
      }
    
      // 对象锁 synchronized (this)
      public void buy04() {
        synchronized (this){
          buy();
        }
      }
    
      // 私有锁 synchronized (lock)
      public void buy05() {
        synchronized (lock){
          buy();
        }
      }
    
      public static void buy(){
        if (num > 0) {
          try {
            Thread.sleep((long) (Math.random() * 100));
          } catch (InterruptedException e) {
            e.printStackTrace();
          }
          System.out.println(Thread.currentThread().getName()+": 抢到第" + num-- + "张票...");
        } else {
          System.out.println(Thread.currentThread().getName()+": 票已售罄...");
        }
      }
    
      public static void main(String[] args) {
        final Ticket ticket = new Ticket();
        for (int i = 0; i < 200; i++) { 
    //      new Thread(() -> { ticket.buy01(); }).start();
    //      new Thread(() -> { ticket.buy02(); }).start();
    //      new Thread(() -> { ticket.buy03(); }).start();
    //      new Thread(() -> { ticket.buy04(); }).start();
          new Thread(() -> { ticket.buy05(); }).start();
        }
      }
    }
    

    依次放开注释,自己玩玩看吧~

    synchronized加锁方式有很多弊端:

    1. A线程获得锁,B线程只能进入阻塞状态,不能取消等待.

    2. A线程进行写操作,B C 线程进行读操作.读写操作会发生冲突,读读操作也会有冲突

    2.Lock接口

    在concurrent包下面有一个Lock接口,接口规范中定义的方法可以解决上边synchronized所带来的问题.接口有6个实现类如下图所示:

     


     

     

    package java.util.concurrent.locks;
    public interface Lock {
        void lock();
        void lockInterruptibly() throws InterruptedException;
        boolean tryLock();
        boolean tryLock(long time, TimeUnitunit) throws InterruptedException;
        void unlock();
        Condition newCondition();
    }
    
    • lock 获取锁,如果其他线程获得锁,则进行等待.但需要主动释放锁unlock

    • lockInterruptibly 可中断锁,在线程等待过程中,可以调用interrupt()方法中断等待.如果已获得锁是不能被中断的.

    • tryLock 判断是否获得锁,获得返回true,否则返回false

    • tryLock(long time, TimeUnitunit) 在指定时间内判断是否获得锁

    • unlock 释放锁

    • newCondition 条件

    3.ReentrantLock重入锁

    ReentrantLock 是Lock的实现类,下面是使用示例:

    1. private Lock lock = new ReentrantLock();

    2. lock.lock();// 获取锁

    3. finally中调用lock.unlock();// 释放锁

    package thread;
    
    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    /**
     * @Author lyf
     * @Date 2018/11/17 0017 14:13
     */
    public class MyLock {
      private static int num = 10;
      private Lock lock = new ReentrantLock();
    
      public void buy01() {
        lock.lock();// 获取锁
        try {
          if (num > 0) {
            Thread.sleep((long) (Math.random() * 100));
            System.out.println(Thread.currentThread().getName() + ": 抢到第" + num-- + "张票...");
          } else {
            System.out.println(Thread.currentThread().getName() + ": 票已售罄...");
          }
        } catch (InterruptedException e) {
          e.printStackTrace();
        } finally {
          lock.unlock();// 释放锁
        }
      }
    
      public static void main(String[] args) {
        final MyLock myLock = new MyLock();
        for (int i = 0; i < 200; i++) {
      	new Thread(() -> { myLock.buy01(); }, "线程"+i).start();
         }
      }
    }
    

     


     

     

    使用lockInterruptibly获得锁,在线程等待过程中,可以被打断.

    public void buy03() throws InterruptedException {
      lock.lockInterruptibly();// 获取锁
      try {
          Thread.sleep(2000);
          if (num > 0) {
            System.out.println(Thread.currentThread().getName() + ": 抢到第" + num-- + "张票...");
          } else {
            System.out.println(Thread.currentThread().getName() + ": 票已售罄...");
          }
      } finally {
        lock.unlock();// 释放锁
      }
    }
    
    Thread t1 = new Thread(()->{
      try {
        myLock.buy03();
      } catch (InterruptedException e) {
        System.out.println(Thread.currentThread().getName()+"被打断...");
      }
    }, "线程1");
    t1.start();// 启动线程
    Thread.sleep(1000);
    t1.interrupt();// 打断线程
    

     


     

     

    4.ReentrantReadWriteLock读写锁

    读写锁可以实现:

    • 读读不冲突

    • 写写互斥

    • 读写互斥

    package thread;
    
    import java.util.concurrent.locks.ReadWriteLock;
    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();// 写语句
        }
      }
    }
    

    单独执行读语句1:

    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();// 写语句
    }
    

     


     

     

    单独执行写语句:

    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();// 写语句
    }
    

     


     

     

    同时运行 读语句1 读语句2 写语句:

    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();// 写语句
    }
    

     


     

     

    参考资料

  • 相关阅读:
    后缀数组模板
    UVALive
    蓝桥杯 拿糖果
    蓝桥杯 矩阵乘法(区间DP)
    51nod 矩阵乘法
    13.boost有向无向图邻接表表示
    12.boost有向图无向图(矩阵法)
    11.使用boostregex遭遇无法打开libboost_regex-vc120-mt-sgd-1_62.lib的问题
    10.ref regex unordered_set smartpoint
    9.variant move function change_cast
  • 原文地址:https://www.cnblogs.com/linyufeng/p/9992134.html
Copyright © 2011-2022 走看看