线程同步机制

线程安全问题

单线程程序是不会出现线程安全问题的,例如:一个电影院售票处卖编号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释放锁
posted @ 2020-10-29 21:57  小明-o3rr0r  阅读(74)  评论(0编辑  收藏  举报