一.Lock接口
常用方法
Lock提供了一个更加面对对象的锁,在该锁中提供了更多的操作锁的功能。
使用Lock接口,以及其中的lock()方法和unlock()方法替代同步,对电影院卖票案例中Ticket类进行如下代码修改:
public class Ticket implements Runnable { //共100票 int ticket = 100; //创建Lock锁对象 Lock ck = new ReentrantLock(); @Override public void run() { //模拟卖票 while(true){ //synchronized (lock){ ck.lock(); if (ticket > 0) { //模拟选坐的操作 try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName() + "正在卖票:" + ticket--); } ck.unlock(); //} } }}
二.死锁
同步锁使用的弊端:当线程任务中出现了多个同步(多个锁)时,如果同步中嵌套了其他的同步。这时容易引发一种现象:程序出现无限等待,这种现象我们称为死锁。这种情况能避免就避免掉。
public class LockA { private LockA(){} public final static LockA locka=new LockA();}
public class LockB { private LockB(){} public final static LockB lockb=new LockB();}
//线程任务类public class DeadLock implements Runnable{ private int i=0; public void run() { while(true){ if(i%2==0){ //先进A同步,再进B同步 synchronized(LockA.locka){ System.out.println("if....locka"); synchronized (LockB.lockb) { System.out.println("if....lockb"); } } }else{ //先进B同步,再进A同步 synchronized(LockB.lockb){ System.out.println("else....lockb"); synchronized (LockA.locka) { System.out.println("else....locka"); } } } i++; } }}
//测试类public class Demo01 { public static void main(String[] args) { DeadLock d1=new DeadLock(); Thread t0=new Thread(d1); Thread t1=new Thread(d1); t0.start(); t1.start(); }}
三.等待唤醒机制
线程之间的通信:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同。通过一定的手段使各个线程能有效的利用资源。而这种手段即—— 等待唤醒机制。
等待唤醒机制所涉及到的方法:
①wait() :等待,将正在执行的线程释放其执行资格 和 执行权,并存储到线程池中。
②notify():唤醒,唤醒线程池中被wait()的线程,一次唤醒一个,而且是任意的。
③notifyAll(): 唤醒全部:可以将线程池中的所有wait() 线程都唤醒。
唤醒的意思就是让线程池中的线程具备执行资格。这些方法都是在同步中才有效。同时这些方法在使用时必须标明所属锁,这样才可以明确出这些方法操作的到底是哪个锁上的线程。
这些方法被定义在了Object类中,因为这些方法在使用时,必须要标明所属的锁,而锁又可以是任意对象。能被任意对象调用的方法一定定义在Object类中。
如上图说示,输入线程向Resource中输入name ,sex , 输出线程从资源中输出,先要完成的任务是:
1.当input发现Resource中没有数据时,开始输入,输入完成后,叫output来输出。如果发现有数据,就wait();
2.当output发现Resource中没有数据时,就wait() ;当发现有数据时,就输出,然后,叫醒input来输入数据。
//模拟资源类public class Resource { public String name; public int age; public boolean flag; }
//Input类public class Input implements Runnable{ //对resource进行赋值 private Resource r; public Input(){} public Input(Resource r){ this.r=r; } public void run() { int i=0; while(true){ synchronized (r) { if(r.flag){ try { r.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } if(i%2==0){ r.name="张三"; r.age=18; }else{ r.name="lisi"; r.age=81; } r.flag=true; r.notify(); } i++; } }}
//Output类public class Output implements Runnable{ private Resource r; public Output(){} public Output(Resource r){ this.r=r; } public void run() { //对resource输出 while(true){ synchronized (r) { //判断标记 if(!r.flag){ try { r.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(r.name+"..."+r.age); r.flag = false; r.notify(); } } } }
//测试类public class Demo01 { public static void main(String[] args) { Resource r=new Resource(); Input in=new Input(r); Output out=new Output(r); Thread tin=new Thread(in); Thread tout=new Thread(out); tin.start(); tout.start(); }}