共享模型之管程(4)

简介: 共享模型之管程

共享模型之管程(3)https://developer.aliyun.com/article/1530876

可打断

如果某个线程处于阻塞状态,可以调用其interrupt方法让其停止阻塞,获得锁失败

简而言之就是:处于阻塞状态的线程,被打断了就不用阻塞了,直接停止运行

public static void main(String[] args) {
    ReentrantLock lock = new ReentrantLock();
    Thread t1 = new Thread(()-> {
      try {
        //加锁,可打断锁
        //如果没有竞争那么此方法就会获取lock对象锁
        //如果有竞争就进入阻塞队列,可以被其他线程用interrupt打断
        lock.lockInterruptibly();
      } catch (InterruptedException e) {
        e.printStackTrace();
                //被打断,返回,不再向下执行
        return;
      }finally {
        //释放锁
        lock.unlock();
      }
    });
    lock.lock();
    try {
      t1.start();
      Thread.sleep(1000);
      //打断
      t1.interrupt();
    } catch (InterruptedException e) {
      e.printStackTrace();
    } finally {
      lock.unlock();
    }
  }

主要防止线程死等

锁超时

使用lock.tryLock方法会返回获取锁是否成功。如果成功则返回true,反之则返回false。

并且tryLock方法可以指定等待时间,参数为:tryLock(long timeout, TimeUnit unit), 其中timeout为最长等待时间,TimeUnit为时间单位

简而言之就是:获取失败了、获取超时了或者被打断了,不再阻塞,直接停止运行

不设置等待时间

public static void main(String[] args) {
    ReentrantLock lock = new ReentrantLock();
    Thread t1 = new Thread(()-> {
            //未设置等待时间,一旦获取失败,直接返回false
      if(!lock.tryLock()) {
        System.out.println("获取失败");
                //获取失败,不再向下执行,返回
        return;
      }
      System.out.println("得到了锁");
      lock.unlock();
    });
    lock.lock();
    try{
      t1.start();
      Thread.sleep(3000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    } finally {
      lock.unlock();
    }
  }

设置等待时间

public static void main(String[] args) {
    ReentrantLock lock = new ReentrantLock();
    Thread t1 = new Thread(()-> {
      try {
        //判断获取锁是否成功,最多等待1秒
        if(!lock.tryLock(1, TimeUnit.SECONDS)) {
          System.out.println("获取失败");
          //获取失败,不再向下执行,直接返回
          return;
        }
      } catch (InterruptedException e) {
        e.printStackTrace();
        //被打断,不再向下执行,直接返回
        return;
      }
      System.out.println("得到了锁");
      //释放锁
      lock.unlock();
    });
    lock.lock();
    try{
      t1.start();
      //打断等待
      t1.interrupt();
      Thread.sleep(3000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    } finally {
      lock.unlock();
    }
  }Copy
公平锁

在线程获取锁失败,进入阻塞队列时,先进入的会在锁被释放后先获得锁。这样的获取方式就是公平的。

//默认是不公平锁,需要在创建时指定为公平锁
ReentrantLock lock = new ReentrantLock(true);
条件变量

synchronized 中也有条件变量,就是我们讲原理时那个 waitSet 休息室,当条件不满足时进入waitSet 等待

ReentrantLock 的条件变量比 synchronized 强大之处在于,它是支持多个条件变量的,这就好比

  • synchronized 是那些不满足条件的线程都在一间休息室等消息
  • 而 ReentrantLock 支持多间休息室,有专门等烟的休息室、专门等早餐的休息室、唤醒时也是按休息室来唤 醒

使用要点:

  • await 前需要获得锁
  • await 执行后,会释放锁,进入 conditionObject 等待
  • await 的线程被唤醒(或打断、或超时)取重新竞争 lock 锁
  • 竞争 lock 锁成功后,从 await 后继续执
static Boolean judge = false;
public static void main(String[] args) throws InterruptedException {
  ReentrantLock lock = new ReentrantLock();
  //获得条件变量
  Condition condition = lock.newCondition();
  new Thread(()->{
    lock.lock();
    try{
      while(!judge) {
        System.out.println("不满足条件,等待...");
        //等待
        condition.await();
      }
    } catch (InterruptedException e) {
      e.printStackTrace();
    } finally {
      System.out.println("执行完毕!");
      lock.unlock();
    }
  }).start();
  new Thread(()->{
    lock.lock();
    try {
      Thread.sleep(1);
      judge = true;
      //释放
      condition.signal();
    } catch (InterruptedException e) {
      e.printStackTrace();
    } finally {
      lock.unlock();
    }
  }).start();
}
通过Lock与AQS实现可重入锁
public class MyLock implements Lock {
   private static class Sync extends AbstractQueuedSynchronizer {
      @Override
      protected boolean tryAcquire(int arg) {
         if (getExclusiveOwnerThread() == null) {
            if (compareAndSetState(0, 1)) {
               setExclusiveOwnerThread(Thread.currentThread());
               return true;
            }
            return false;
         }
         if (getExclusiveOwnerThread() == Thread.currentThread()) {
            int state = getState();
            compareAndSetState(state, state + 1);
            return true;
         }
         return false;
      }
      @Override
      protected boolean tryRelease(int arg) {
         if (getState() <= 0) {
            throw new IllegalMonitorStateException();
         }
         if (getExclusiveOwnerThread() != Thread.currentThread()) {
            throw new IllegalMonitorStateException();
         }
         int state = getState();
         if (state == 1) {
            setExclusiveOwnerThread(null);
            compareAndSetState(state, 0);
         } else {
            compareAndSetState(state, state - 1);
         }
         return true;
      }
      @Override
      protected boolean isHeldExclusively() {
         return getState() >= 1;
      }
      public Condition newCondition() {
         return new ConditionObject();
      }
   }
   Sync sync = new Sync();
   @Override
   public void lock() {
      sync.acquire(1);
   }
   @Override
   public void lockInterruptibly() throws InterruptedException {
      sync.acquireInterruptibly(1);
   }
   @Override
   public boolean tryLock() {
      return sync.tryAcquire(1);
   }
   @Override
   public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
      return sync.tryAcquireNanos(1, time);
   }
   @Override
   public void unlock() {
      sync.release(1);
   }
   @Override
   public Condition newCondition() {
      return sync.newCondition();
   }
}
class Main {
   static int num = 0;
   public static void main(String[] args) throws InterruptedException, IOException {
      MyLock lock = new MyLock();
      Object syncLock = new Object();
      Thread t1 = new Thread(() -> {
         for (int i = 0; i < 10000; i++) {
            lock.lock();
            try {
               lock.lock();
               try {
                  lock.lock();
                  try {
                     num++;
                  } finally {
                     lock.unlock();
                  }
               } finally {
                  lock.unlock();
               }
            } finally {
               lock.unlock();
            }
         }
      });
      Thread t2 = new Thread(() -> {
         for (int i = 0; i < 10000; i++) {
            lock.lock();
            try {
               lock.lock();
               try {
                  lock.lock();
                  try {
                     num--;
                  } finally {
                     lock.unlock();
                  }
               } finally {
                  lock.unlock();
               }
            } finally {
               lock.unlock();
            }
         }
      });
      t1.start();
      t2.start();
      t1.join();
      t2.join();
      int x = 0;
   }
}Copy

13、同步模式之顺序控制

Wait/Notify版本

static final Object LOCK = new Object();
//判断先执行的内容是否执行完毕
static Boolean judge = false;
public static void main(String[] args) {
  new Thread(()->{
    synchronized (LOCK) {
      while (!judge) {
        try {
          LOCK.wait();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
      System.out.println("2");
    }
  }).start();
  new Thread(()->{
    synchronized (LOCK) {
      System.out.println("1");
      judge = true;
               //执行完毕,唤醒所有等待线程
      LOCK.notifyAll();
    }
  }).start();
}Copy

使用park往背包放东西

交替输出

wait/notify版本

public class Test4 {
  static Symbol symbol = new Symbol();
  public static void main(String[] args) {
    new Thread(()->{
      symbol.run("a", 1, 2);
    }).start();
    new Thread(()->{
      symbol.run("b", 2, 3);
    }).start();
    symbol.run("c", 3, 1);
    new Thread(()->{
    }).start();
  }
}
class Symbol {
  public synchronized void run(String str, int flag, int nextFlag) {
    for(int i=0; i<loopNumber; i++) {
      while(flag != this.flag) {
        try {
          this.wait();
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
      System.out.println(str);
      //设置下一个运行的线程标记
      this.flag = nextFlag;
      //唤醒所有线程
      this.notifyAll();
    }
  }
  /**
   * 线程的执行标记, 1->a 2->b 3->c
   */
  private int flag = 1;
  private int loopNumber = 5;
  public int getFlag() {
    return flag;
  }
  public void setFlag(int flag) {
    this.flag = flag;
  }
  public int getLoopNumber() {
    return loopNumber;
  }
  public void setLoopNumber(int loopNumber) {
    this.loopNumber = loopNumber;
  }
}Copy

await/signal版本

public class Test5 {
  static AwaitSignal awaitSignal = new AwaitSignal();
  static Condition conditionA = awaitSignal.newCondition();
  static Condition conditionB = awaitSignal.newCondition();
  static Condition conditionC = awaitSignal.newCondition();
  public static void main(String[] args) {
    new Thread(()->{
      awaitSignal.run("a", conditionA, conditionB);
    }).start();
    new Thread(()->{
      awaitSignal.run("b", conditionB, conditionC);
    }).start();
    new Thread(()->{
      awaitSignal.run("c", conditionC, conditionA);
    }).start();
    try {
      Thread.sleep(1000);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    awaitSignal.lock();
    try {
            //唤醒一个等待的线程
      conditionA.signal();
    }finally {
      awaitSignal.unlock();
    }
  }
}
class AwaitSignal extends ReentrantLock{
  public void run(String str, Condition thisCondition, Condition nextCondition) {
    for(int i=0; i<loopNumber; i++) {
      lock();
      try {
                //全部进入等待状态
        thisCondition.await();
        System.out.print(str);
        nextCondition.signal();
      } catch (InterruptedException e) {
        e.printStackTrace();
      } finally {
        unlock();
      }
    }
  }
  private int loopNumber=5;
  public int getLoopNumber() {
    return loopNumber;
  }
  public void setLoopNumber(int loopNumber) {
    this.loopNumber = loopNumber;
  }
}

共享模型之管程(5)https://developer.aliyun.com/article/1530883

相关文章
WK
|
23天前
|
并行计算 调度 Python
GIL和线程之间的区别是什么
全局解释器锁(GIL)与线程在Python中具有不同角色。GIL作为CPython中的互斥锁,确保同一时间只有一个线程执行Python字节码,简化内存管理但限制多线程并行性;线程则是程序执行的最小单位,允许多个任务并发运行。GIL影响整个解释器,使多线程串行化;线程则代表独立执行流,受GIL制约。GIL在计算密集型任务中成为瓶颈,但在I/O密集型任务中多线程仍可提升性能。理解两者差异有助于优化多线程应用。
WK
24 0
|
5月前
|
并行计算 Java Linux
工作2年,有些人竟然还不懂进程、线程、协程之间的关系!
我们都知道计算机的核心是CPU,它承担了所有的计算任务;而操作系统是计算机的管理者,它负责任务的调度、资源的分配和管理,统领整个计算机硬件;应用程序则是具有某种功能的程序,程序是运行于操作系统之上的。
40 0
|
4月前
|
Java
共享模型之管程(5)
共享模型之管程
21 0
|
4月前
|
存储 安全 Java
共享模型之管程(1)
共享模型之管程
20 0
|
4月前
|
Java
共享模型之管程(3)
共享模型之管程
37 0
|
4月前
|
消息中间件 Java API
共享模型之管程(2)
共享模型之管程
30 0
|
Linux 编译器 调度
【线程概念和线程控制】(一)
【线程概念和线程控制】(一)
116 0
|
存储
【线程概念和线程控制】(二)
【线程概念和线程控制】(二)
62 0
|
存储 Linux 调度
多线程——线程概念和线程控制
什么是线程,POSIX线程库,线程控制:pthread_create线程创建,pthread_exit线程终止,pthread_join线程回收,pthread_cancel线程取消,pthread_detach线程分离。线程id和地址空间分局,C++语言级别的多线程,二次封装线程库
100 0
多线程——线程概念和线程控制
|
消息中间件 并行计算 调度
多线程和进程的关系
多线程和进程的关系