java多线程(死锁,lock接口,等待唤醒机制)

Posted 技术研究与问题解决

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java多线程(死锁,lock接口,等待唤醒机制)相关的知识,希望对你有一定的参考价值。

一.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();
    }
}
复制代码

以上是关于java多线程(死锁,lock接口,等待唤醒机制)的主要内容,如果未能解决你的问题,请参考以下文章

多线程等待唤醒机制Lock,condition

多线程等待唤醒机制之生产消费者模式

多线程等待唤醒机制之生产消费者模式

Java——线程锁,死锁,等待唤醒机制

多线程之间的通信(等待唤醒机制Lock 及其它线程的方法)

多线程的等待唤醒(使用监视器)