zoukankan      html  css  js  c++  java
  • 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();
        }
    }
    复制代码
  • 相关阅读:
    oracle 数据库、实例、服务名、SID
    查看oracle数据库服务器的名字
    oracle表复制
    Oracle 备份、恢复单表或多表数据步骤
    如何查询一个表中有哪些列全为空
    mysql当查询某字段结果为空并赋值
    NoSQL初探之人人都爱Redis:(1)Redis简介与简单安装
    《大型网站技术架构》读书笔记四:瞬时响应之网站的高性能架构
    《大型网站技术架构》读书笔记三:大型网站核心架构要素
    《大型网站技术架构》读书笔记二:大型网站架构模式
  • 原文地址:https://www.cnblogs.com/liuys635/p/10586785.html
Copyright © 2011-2022 走看看