• 菜鸡的Java笔记


    线程的同步与死锁 (同步 synchronization,死锁 deadlock)
            多线程的操作方法
        
            1.线程同步的产生与解决
            2.死锁的问题

        同步问题的的引出
            如果要想进行同步的操作,那么很明显就是多个线程需要访问同一资源
            
            范例:以卖票程序为例

    package cn.mysterious.study3;
    
    class MyThread implements Runnable{
        private int ticket = 5;
        @Override
        public void run() {
        // TODO Auto-generated method stub
            for (int i = 0; i < 10; i++) {
                if (this.ticket > 0) {
                    System.out.println(Thread.currentThread().getName() + ",ticket = "+this.ticket --);
                }
            }
        }
    }
    public class StudyThread {
    
        public static void main(String[] args) throws Exception {
            MyThread mt = new MyThread();
            Thread t1 = new Thread(mt,"票贩子A");
            Thread t2 = new Thread(mt,"票贩子B");
            Thread t3 = new Thread(mt,"票贩子C");
            t1.start();
            t2.start();
            t3.start();
        }
    }

               
                于是下面开始挖掘本程序所存在的问题
                
            范例:观察程序的问题

    package cn.mysterious.study3;
    
    class MyThread implements Runnable{
        private int ticket = 5;
        @Override
        public void run() {
        // TODO Auto-generated method stub
            for (int i = 0; i < 10; i++) {
                if (this.ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ",ticket = "+this.ticket --);
                }
            }
        }
    }
    public class StudyThread {
    
        public static void main(String[] args) throws Exception {
            MyThread mt = new MyThread();
            Thread t1 = new Thread(mt,"票贩子A");
            Thread t2 = new Thread(mt,"票贩子B");
            Thread t3 = new Thread(mt,"票贩子C");
            t1.start();
            t2.start();
            t3.start();
        }
    }
    //    结果出现了负数

                   
            bane这样的操作就属于线程的不同步的操作,所以发现多个线程操作时必须要考虑到资源同步的问题

        实现同步操作
            整个代码之中发现有一个逻辑上的流程错误了,以上的程序中,将判断是否有票,延迟,卖票分为了三个部分
            那么实际上每个线程如果要执行卖票的话,其他线程应该等待当前线程执行完毕后才可以进入
            
            如果要想在若干个代码上实现锁这个概念,那么就需要通过使用同步代码块或者同步方法来解决
            
            1.同步代码块
                使用 synchronized 关键字定义的代码块就称为同步代码块,但是在进行同步的时候需要设置有一个同步对象,那么往往可以使用 this 同步当前对象
                

    package cn.mysterious.study3;
    
    class MyThread implements Runnable{
        private int ticket = 500;
        @Override
        public void run() {
        // TODO Auto-generated method stub
            for (int i = 0; i < 1000; i++) {
                synchronized (this) {
                    if (this.ticket > 0) {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() + ",ticket = "+this.ticket --);
                    }
                }
            }
        }
    }
    public class StudyThread {
    
        public static void main(String[] args) throws Exception {
            MyThread mt = new MyThread();
            Thread t1 = new Thread(mt,"票贩子A");
            Thread t2 = new Thread(mt,"票贩子B");
            Thread t3 = new Thread(mt,"票贩子C");
            t1.start();
            t2.start();
            t3.start();
        }
    }

                   
                加入同步之后整个代码执行的速度已经变慢了,而已不像美誉同步的时候那样多个线程一起进入到方法之中
                异步的执行速度要快于同步的执行速度,但是异步的操作属于非线程安全的操作,而同步的操作属于线程的安全操作
                
            2.同步方法    
                但是对于同步操作,除了用于代码块定义之外,也可以在方法上定义同步操作
                    

    package cn.mysterious.study3;
    
    class MyThread implements Runnable{
        private int ticket = 500;
        @Override
        public void run() {
        // TODO Auto-generated method stub
            for (int i = 0; i < 1000; i++) {
                sale();
            }
        }
        public synchronized void sale(){ // 卖票
            if (this.ticket > 0) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + ",ticket = "+this.ticket --);
            }
        }
    }
    public class StudyThread {
    
        public static void main(String[] args) throws Exception {
            MyThread mt = new MyThread();
            Thread t1 = new Thread(mt,"票贩子A");
            Thread t2 = new Thread(mt,"票贩子B");
            Thread t3 = new Thread(mt,"票贩子C");
            t1.start();
            t2.start();
            t3.start();
        }
    }

               
                在多个线程访问同一资源时一定要考虑到数据的同步问题,同步就使用 synchronized 关键字
        死锁分析(了解)
            很明显,死锁是一种不确定的状态,对于死锁的操作应该出现的越少越好,下面的代码只是一个死锁的演示,代码不做任何实际的意义
            
     

    package cn.mysterious.study3;
    
    class Kidnapper{  // 绑匪
        public synchronized void say(Landlord dz){
            System.out.println(" 绑匪说:给我3亿美金,放了你儿子!");
            dz.get();
        }
        public synchronized void get(){
            System.out.println("绑匪得到钱");
        }
    }
    class Landlord{  // 地主
        public synchronized void say(Kidnapper bf){
            System.out.println(" 地主说:放了我儿子,再给钱!");
            bf.get();
        }
        public synchronized void get(){
            System.out.println("救回.....");
        }
    }
    public class StudyThread implements Runnable{
        private Kidnapper bf = new Kidnapper();
        private Landlord dz = new Landlord();
        public StudyThread (){
            new Thread(this).start();
            dz.say(bf);
        }
        public static void main(String[] args) throws Exception {
            new StudyThread();
        }
        @Override
        public void run() {
            // TODO Auto-generated method stub
            bf.say(dz);
        }
    }

               
            面试题:请问多个线程访问同一资源时可能带来什么问题?以及会产生什么样的附加问题?
                 多个线程访同一资源时必须考虑同步问题,可以使用 synchronized 定义同步代码块或者是同步方法
                 程序中如果出现过多的同步那么就将产生死锁
                
        总结
            如果看见 synchronized 声明的方法,一定有爱记住这是一个同步方法,属于线程安全的操作

  • 相关阅读:
    debian 9安装细节
    gnome环境设置
    Linux之crontab定时任务
    独显切换进入图形界面思路
    pycharm多行注释
    如何在cmd中运行.py文件
    如何在 PyCharm 中设置 Python 代码模板
    在R中使用Keras和TensorFlow构建深度学习模型
    kubernetes cert-manager installation
    Simple way to create a tunnel from one local port to another?
  • 原文地址:https://www.cnblogs.com/mysterious-killer/p/10124102.html
Copyright © 2020-2023  润新知