zoukankan      html  css  js  c++  java
  • 线程同步机制

    线程安全问题

    单线程程序是不会出现线程安全问题的,例如:一个电影院售票处卖编号1-100的门票,不会有问题。

    多线程程序,没有访问共享数据,也不会产生线程安全问题,例如:三个电影售票处卖标号1-100的门票,但门票编号不同,也不会出现问题。

    多线程程序访问了共享的数据,就会产生线程安全问题,例如:三个电影售票处卖编号1-100的门票,门票编号相同,就会出现问题。

    线程安全问题的代码实现

    package M1.day27.day28;
    /*
    实现卖票案例 
    */
    public class RunnableImpl implements Runnable{    
        //定义一个多线程的票源    
        private int ticket = 100;    
        //设置线程任务(卖票)    
        @Override    
        public void run(){        
            //创建死循环,让卖票一直进行下去        
            while (true){            
                //为了提高安全事件出现概率,让程序睡眠            
                try {                
                    Thread.sleep(10);            
                } catch (InterruptedException e) {                
                    e.printStackTrace();            
                }            
                //先判断票是否存在            
                if (ticket>0){                
                    //票存在,卖票                
                    System.out.println(Thread.currentThread().getName()+"正在卖"+ticket+"号票");                
                    ticket--;            
                }else break;        
            }    
        }
    }
    
    package M1.day27.day28;
    /*
    模拟卖票案例创建三个线程,同时开启,对共享的票进行出售 
    */
    public class Ticket {    
        public static void main(String[] args) {       
            //创建Runnable接口的实现类对象        
            RunnableImpl run = new RunnableImpl();        
            //创建Thread类对象,构造方法中传递Runnable接口的实现类对象        
            Thread t0 = new Thread(run);        
            Thread t1 = new Thread(run);        
            Thread t2 = new Thread(run);        
            //调用start方法开启多线程        
            t0.start();        
            t1.start();        
            t2.start();    
        }
    }
    

    线程安全问题是不能产生的,我们可以让一个线程在访问共享数据的时候,无论是否失去了cpu的执行权,让其他线程只能等待,等待该线程执行完后,其他线程再进行该操作。

    同步代码块

    同步代码块:synchronized关键字可以用于方法中的某个区块中,表示只对这个取快递资源实行互斥访问。

    格式:
    synchronized(同步锁){
    可能会出现线程安全问题的代码(访问了共享数据的代码)
    }

    注意:

    1. 通过代码块中的锁对象,可以使用任意的对象
    2. 但是必须保证多个线程使用的锁对象是同一个
    3. 锁对象作用:
      把同步代码块锁住,会让一个线程在同步代码块中执行。

    代码演示:

    package M1.day27.day28;
    /*
    实现卖票案例 
    */
    public class RunnableImpl implements Runnable{    
        //定义一个多线程的票源    
        private int ticket = 100;    
        //创建一个锁对象    
        Object obj = new Object();    
        //设置线程任务(卖票)    
        @Override    
        public void run(){        
            //创建死循环,让卖票一直进行下去        
            while (true){            
                //同步代码块            
                synchronized (obj){                
                    //先判断票是否存在                
                    if (ticket>0){                    
                        //票存在,卖票                    
                        //为了提高安全事件出现概率,让程序睡眠                    
                        try {                        
                            Thread.sleep(10);                    
                        } catch (InterruptedException e) {                        
                            e.printStackTrace();                    
                        }                                        
                        System.out.println(Thread.currentThread().getName()+"正在卖"+ticket+"号票");                    
                        ticket--;                
                    }else break;            
                }        
            }    
        }
    }
    

    同步技术的原理

    使用了一个锁对象,这个锁对象也叫对象所,也叫对象监视器。

    同步中的线程,没有执行完毕不会释放所,同步外的程序,没有锁对象进去不去同步。

    同步保证了只能有一个线程在同步中执行共享数据,保证了安全。弊端在于,程序频繁的判断锁,获取锁,释放锁会导致程序的效率降低。

    同步方法

    代码演示:

    package M1.day27.day28;
    public class tongbufangfa implements Runnable{    
        private int ticket = 100;    
        @Override    
        public void run(){        
            while (true){            
                payTicket();        
            }    
        }   
        /*    
        定义一个同步方法     
        */    
        public synchronized void payTicket(){        
            if (ticket>0){            
                try {                
                    Thread.sleep(10);            
                } catch (InterruptedException e) {                
                    e.printStackTrace();            
                }            
                System.out.println(Thread.currentThread().getName()+"正在卖"+ticket+"号票");            
                ticket--;        
            }    
        }
    }
    

    同步方法也会把方法内部的代码锁住。
    只让一个线程执行。
    同步方法的锁对象就是实现类对象。

    静态同步方法

    静态同步方法锁对象是谁?
    不能是this
    this是创建对象之后产生的,静态方法优先于对象
    静态方法的锁对象是本类的class属性-->class文件对象(反射)

    Lock锁

    java.util.concurrent.locks是解决线程安全问题的第三种方案。
    java.util.concurrent.locks.lock接口
    lock视线提供了比使用synchronized方法和语句可获得的更广泛的锁定操作。
    lock接口中的方法:
    void lock()获取锁
    void unlock()释放锁

    使用步骤:

    1. 在成员位置创建一个Reentrantloc对象
    2. 在可能会出现安全问题的代码前调用lock接口中的方法lock获取锁
    3. 在可能会出现安全问题的代码前调用lock接口中的方法lock释放锁
    文章未经本人允许,禁止转载。 有技术问题,可加好友讨论。 联系方式:QQ:MjgxMjMxODAzNQ== 微信:bzNycjByLVhpYW9taW5n
  • 相关阅读:
    flask修改flask_wtf使其支持json数据的validation验证
    nsq 初学使用日记
    git的日常使用(补课)
    mysql 学习日记 悲观和乐观锁
    19.10.11学习日记随笔 mysql事务隔离性
    伸展树 Splay 模板
    NOI2004 郁闷的出纳员 Splay
    Size Balanced Tree(SBT) 模板
    HDU 4557 非诚勿扰 队列、(记一次失败的SBT尝试)
    HDU 4006 The kth great number 优先队列、平衡树模板题(SBT)
  • 原文地址:https://www.cnblogs.com/Xiaoming0/p/13899506.html
Copyright © 2011-2022 走看看