一. 锁
锁,是在同步时一个非常重要的概念, 然而注意,锁很容易造成死锁。 如果同步了一个对象的内部,又同步了另外一个对象,那么就很容易造成死锁。 然而,如果在同步了一个对象的内部,又同步了当前的对象,那么会造成死锁吗?
public class Lock1 { public void test() throws Exception{ new Thread(()->{ //同步当前对象 synchronized (this){ while(true){ //锁同一个对象,可以执行第二个同步的代码。 synchronized (this){ System.out.println("进入"); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start(); } public static void main(String[] args) { try { new Lock1().test(); } catch (Exception e) { e.printStackTrace(); } } }
运行程序, 查看控制台输出
并不会造成死锁, 说明在同步对象的内部,可以再次同步当前对象。
二. 实现锁
锁,实际上内部就是一个标识, 如果锁上了,那么标识为true,如果解锁,那么标识就是false.
锁有两种形式, 第一种是已经锁上了,无论是谁,包括它自己,都无法再上锁(非重入锁)。
第二种是已经上锁了, 除了它自己之外,其他的线程都不能上锁(重入锁)。
第一种情况,在上锁时,先检测一下标识,如果已经锁上了,标识已经为true了, 那么就不能重新上锁了,必须等待。
第二种情况,在上锁时,先检测一下标识,如果已经锁上了,并且锁上的线程并不是自己,那么就不能重新上锁,必须等待。
二.一 非重入锁
public class Lock2 { private Lock lock=new Lock(); //进行加锁和去锁 public void a(){ lock.lock(); //去调用另一个加锁的方法 doSomThing(); lock.unlock(); } public void doSomThing(){ lock.lock(); System.out.println("做一些事情"); lock.unlock(); } public static void main(String[] args) { Lock2 lock2=new Lock2(); lock2.a(); } } /** * 锁类 */ class Lock{ //有一个标识 private boolean flag=false; public synchronized void lock(){ //已经上锁了,那么就必须等待。 while(flag){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } flag=true; } public synchronized void unlock(){ flag=false; notify(); } }
运行程序,没有任何的输出,发现,程序进入了死锁。
二.二 重入锁
重入锁里面有三个标识,一个是 是否锁的标识 flag, 一个是锁的那个线程,另外一个是锁的次数。
public class Lock3 { private ReLock lock=new ReLock(); //进行加锁和去锁 public void a(){ lock.lock(); //1 System.out.println(lock.getCount()); doSomThing(); //1 System.out.println(lock.getCount()); lock.unlock(); //0 System.out.println(lock.getCount()); } public void doSomThing(){ lock.lock(); System.out.println("做一些事情"); //2 System.out.println(lock.getCount()); lock.unlock(); //1 System.out.println(lock.getCount()); } public static void main(String[] args) { Lock3 lock3=new Lock3(); lock3.a(); //0 System.out.println(lock3.lock.getCount()); // lock2.doSomThing(); } } /** * 重入锁 */ class ReLock{ //有一个标识位 private boolean flag=false; //记录一下,锁的那个线程 private Thread localLockThread=null; //记录一下,锁的次数 private int count=0; public synchronized void lock(){ Thread temp=Thread.currentThread(); //已经锁上了,并且不是当前的线程,那么就等待了。 while(flag&&temp!=localLockThread){ try { this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //赋值 localLockThread=temp; count++; flag=true; } public synchronized void unlock(){ Thread temp=Thread.currentThread(); //如果相同,才可以解锁。 if(localLockThread==temp){ count--; //如果已经没有次数了,那么才是真正的释放锁。 if(count==0){ localLockThread=null; flag=false; notify(); } } } public int getCount() { return count; } }
运行程序
三. 多线程提供锁 ReentrantLock
多线程提供了锁, ReentrantLock , 用法基本与 ReLock 差不多。
关于 ReentrantLock 的用法,后面老蝴蝶会讲解的, 现在只讲解一下实现锁的小例子。
public class Lock4 { //内部封装了 标识,线程和次数 private ReentrantLock lock=new ReentrantLock(); public void a(){ lock.lock(); System.out.println(lock.getHoldCount()); doSomeThing(); System.out.println(lock.getHoldCount()); lock.unlock(); System.out.println(lock.getHoldCount()); } public void doSomeThing(){ lock.lock(); System.out.println(lock.getHoldCount()); System.out.println("做一些事件"); lock.unlock(); System.out.println(lock.getHoldCount()); } public static void main(String[] args) { Lock4 lock4=new Lock4(); lock4.a(); System.out.println(lock4.lock.getHoldCount()); } }
运行程序,
谢谢您的观看,如果喜欢,请关注我,再次感谢 !!!