Java 多线程 同步锁

多线程 处理同一资源

典型案例   不同途径 对某场电影的票数 进行售卖       假设没有退票    各线程的任务都是售卖票 使票数不断减少

为避免 多线程售同一张票   出现票数被减为负   引入“线程同步”     

同步 保证了 安全性     因为没有锁的线程不能执行   (线程只有先拿到同步锁 才能执行售票 ,  其它线程 没有拿到同步锁  则不能执行   存在了先后顺序) 

同步方法的执行  需要进行 同步锁是否拥有的判断   因此这种添加了synchronized关键字修饰的方法  这种方法的运行速度较慢(StringBuilder类的方法  都是不同步的方法   StringBuffer类的 方法 都是同步的方法)

同步锁   其专业词汇 被称为  对象监视器   ------ java.lang包下的异常类  IllegaMonitorStateEXception 无效的监视器状态异常

 

 

Java 线程同步技术    接口Lock     同步方法  同步代码块

同步代码块----代码简化---->同步方法(同步锁 代码中无法看见)---- 即便异常也要保证对象锁能够被释放,“拿取锁+释放锁”明显可见---->接口Lock

 

1.同步代码块

创建任意对象  例如Object obj = new Object()
synchronized(obj){ //线程要操作的共享数据 }

 

public class Tickets implements Runnable{
    
    //定义出售的票源
    private int ticket = 100;
    private Object obj = new Object();
    
    public void run(){
        while(true){
            //线程共享数据,保证安全,加入同步代码块
            synchronized(obj){
            //对票数判断,大于0,可以出售,变量--操作
                if( ticket > 0){
                    try{
                       Thread.sleep(10);
                    }catch(Exception ex){}
                    System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--);
                }
            }
        }
    }
}
/*
 * 多线程并发访问同一个数据资源
 * 3个线程,对一个票资源,出售
 */
public class ThreadDemo {
    public static void main(String[] args) {
        //创建Runnable接口实现类对象
        Tickets t = new Tickets();
        //创建3个Thread类对象,传递Runnable接口实现类
        Thread t0 = new Thread(t);
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        
        t0.start();t1.start();t2.start();
        
    }
}

 

2.同步方法

将同步代码块中的内容抽取到一个方法中
并在该方法的声明上,加入同步关键字 synchronized

同步方法 虽然代码上无法看到“对象锁”,但实质该锁是存在的,通常该锁是本类对象引用 this;如果同步方法是静态方法 ,即被static修饰 ,则该锁不再是 本类对象this,而是类 本类自己.class 属性

   

public class Tickets implements Runnable{

    //定义出售的票源
    private  int ticket = 100;
    
    public void run(){
        while(true){
            payTicket();
        }
    }
    
    /*public  void payTicket(){    
        synchronized(this){
            if( ticket > 0){
                try{
                   Thread.sleep(10);
                }catch(Exception ex){}
                System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--);
            }
        }
    
    }*/
        
    
    
    public  synchronized void payTicket(){    
            if( ticket > 0){
                try{
                   Thread.sleep(10);
                }catch(Exception ex){}
                System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--);
            }
        
    }
    
}

 

 

/*
 *  
 *  问题:
 *    同步方法方法是静态的呢,同步有锁吗,绝对不是this
 *    锁是本类自己.class属性
 */
public class Tickets implements Runnable{

    //定义出售的票源
    private static int ticket = 100;
    
    public void run(){
        while(true){
            payTicket();
        }
    }
    
    public static void payTicket(){    
        synchronized(Tickets.class){
            if( ticket > 0){
                try{
                   Thread.sleep(10);
                }catch(Exception ex){}
                System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--);
            }
        }
    
    }        
    
}

 

3.接口Lock

该接口  来自于java.util.concurrent.locks包

/*
 *  使用JDK1.5 的接口Lock,替换同步代码块,实现线程的安全性
 *  Lock接口方法:
 *  使用接口Lock的 实现类ReentrantLock
 *  先获取锁   接口Lock的lock()方法 
 *  最后释放锁   接口Lock的unlock()方法
 *  
 */
public class Tickets implements Runnable{
    
    //定义出售的票源
    private int ticket = 100;
    
    //在类的成员位置,创建Lock接口的实现类对象
    private Lock lock = new ReentrantLock();
    
    public void run(){
        while(true){
            //调用Lock接口方法lock获取锁
            lock.lock();
            //对票数判断,大于0,可以出售,变量--操作
                if( ticket > 0){
                    try{
                       Thread.sleep(10);
                       System.out.println(Thread.currentThread().getName()+" 出售第 "+ticket--);
                    }catch(Exception ex){
                        
                    }finally{
                        //释放锁,调用Lock接口方法unlock
                        lock.unlock();
                    }
                }            
        }
    }
}
/*
 * 多线程并发访问同一个数据资源
 * 3个线程,对一个票资源,出售
 */
public class ThreadDemo {
    public static void main(String[] args) {
        //创建Runnable接口实现类对象
        Tickets t = new Tickets();
        //创建3个Thread类对象,传递Runnable接口实现类
        Thread t0 = new Thread(t);
        Thread t1 = new Thread(t);
        Thread t2 = new Thread(t);
        
        t0.start();t1.start();t2.start();
        
    }
}

 

posted @ 2020-05-29 11:01  CherryYang  阅读(268)  评论(0)    收藏  举报