线程安全处理的3种方式

一、模拟电影院的票过程假设要播放的电影是 “唐人街探案3”,本次电影的座位共100(电影只能卖100张票)

代码如下:

public class Tickects implements Runnable {
    private int ticket=100;
    public void run() {
    //int ticket=100  自己独有数据 不是共享数据 所以int ticket=100不能写到这个地方
        while(true){
            if(ticket>0){
                try {
                    Thread.sleep(500); //这个地方加sleep睡眠状态
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"售出了第"+ticket--+"张票");
            }
        }
    }
}
public class Demo01 {
    public static void main(String[] args) {
        //创建线程任务
        Tickects t=new Tickects();
        //创建线程对象
        Thread t1=new Thread(t);
        Thread t2=new Thread(t);
        Thread t3=new Thread(t);
        t1.start();
        t2.start();
        t3.start();
    }

运行结果如下:

 

出现的问题:出现重复票  错误票0

解决方法:①同步代码块 使用 synchronized 关键字 (锁对象){可能出现问题的代码}

public class Tickects02 implements Runnable {
    private int ticket=10;
    private Object obj=new Object();
    public void run() {
        while(true){
            synchronized (obj) { //还可以直接用this 结果是一样的 
                //可能发生问题的代码块问题代码
                if(ticket>0){
                    try {
                        Thread.sleep(500);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"售出了第"+ticket--+"张票");
                }
            }    
        }
    }
}

public class Demo02 {
    public static void main(String[] args) {
        //创建线程任务
        Tickects02 t=new Tickects02();
        //创建线程对象
        Thread t1=new Thread(t);
        Thread t2=new Thread(t);
        Thread t3=new Thread(t);
        t1.start();
        t2.start();
        t3.start();
    }
}

② 同步方法

public synchronized void method(){

    可能会产生线程安全问题的代码

}

public class Tickects03 implements Runnable {
    private int ticket=100;
    public void run() {
        while(true){
            sale();     //调用下面这个sale()对象
        }
    }
    //同步方法(内置锁对象this)
    public synchronized void sale(){
        if(ticket>0){
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"售出了第"+ticket--+"张票");
        }
    }
}
public class Demo03 {
    public static void main(String[] args) {
        //创建线程任务
        Tickects03 t=new Tickects03();
        //创建线程对象
        Thread t1=new Thread(t);
        Thread t2=new Thread(t);
        Thread t3=new Thread(t);
        t1.start();
        t2.start();
        t3.start();
    }
}

③用Lock 接口 

public class Tickects04 implements Runnable {
    private int ticket=100;
    //lock 接口实现类对象
    private Lock lock=new ReentrantLock();
    public void run() {
        while(true){
            lock.lock();
            if(ticket>0){
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"售出了第"+ticket--+"张票");
            }
            //释放锁
            lock.unlock();
        }
    }
}
public class Demo04 {
    public static void main(String[] args) {
        //StringBuffer和StringBuilder
        //StringBuffer 速度慢安全 (慢:线程同步)
        //StringBuilder 速度快 不安全 比较适合单线程
        //创建线程任务
        Tickects04 t=new Tickects04();
        //创建线程对象
        Thread t1=new Thread(t);
        Thread t2=new Thread(t);
        Thread t3=new Thread(t);
        t1.start();
        t2.start();
        t3.start();
    }
}

这三种方法打印出结果是相同的:

 

 无重复,无错误票;

欢迎各位大神指点和评论,多多交流;

posted @ 2020-04-26 11:33  丿狂奔的蜗牛  阅读(230)  评论(0编辑  收藏  举报