线程安全的3种方式

1 多线程容易出现问题

举个例子,电影院卖票,一共卖100张票,分3个窗口,用多线程来模拟,看会发生什么?

1-1 创建一个卖票任务,实现Runnable接口

public class Ticket implements Runnable{

//    总共100
    private int ticket = 100;

    @Override
    public void run() {
        while (true){
            if (ticket>0){
                try {
//                    处理卖票耗时
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                String name = Thread.currentThread().getName();
                System.out.println(name+"正在卖票"+ticket--);
            }
        }

    }
}

1-2 创建3个线程,来卖票

public class Test {
    public static void main(String[] args) {
        Ticket ticket = new Ticket();
        Thread t1 = new Thread(ticket, "线程1");
        Thread t2 = new Thread(ticket, "线程2");
        Thread t3 = new Thread(ticket, "线程3");

        t1.start();
        t2.start();
        t3.start();
    }
}

1-3 出现的问题

  • 相同的票被卖了2次,如下图
    屏幕快照 2020-03-12 下午10.08.33.png
  • 不存在的票,如0或者1
    屏幕快照 2020-03-12 下午10.09.42.png
    若有多个线程同时执行写的操作,那么需要考虑线程同步,否则的话,可能影响线程安全。

2 同步代码块 synchronized

synachronized(同步锁){
          需要同步操作的代码
}

2-1 使用同步锁的方式来创建Runnable的实现类

public class Ticket implements Runnable{

//    总共100
    private int ticket = 100;

    Object obj = new Object();

    @Override
    public void run() {
        while (true){
            synchronized (obj){
                if (ticket>0){
                    try {
//                    处理卖票耗时
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    String name = Thread.currentThread().getName();
                    System.out.println(name+"正在卖票"+ticket--);
                }
            }
        }

    }
}

3 使用同步方法来解决线程安全

使用synchronized修饰的方法,就是同步方法,可以保证一个线程执行该方法的同时,其它的线程只能在方法的外边等候

public class Ticket implements Runnable{

//    总共100
    private int ticket = 100;


    @Override
    public void run() {
        while (true){
            sellTicket();
        }

    }

    public synchronized void sellTicket(){
        if (ticket>0){
            try {
//                    处理卖票耗时
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            String name = Thread.currentThread().getName();
            System.out.println(name+"正在卖票"+ticket--);
        }
    }
}

4 使用lock锁

synachronized(同步锁){
          需要同步操作的代码
}

2-1 使用同步锁的方式来创建Runnable的实现类

public class Ticket implements Runnable{

//    总共100
    private int ticket = 100;

Lock lock = new ReentrantLock();    

    @Override
    public void run() {
        while (true){
            lock.lock();
             if (ticket>0){
                    try {
//                    处理卖票耗时
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    String name = Thread.currentThread().getName();
                    System.out.println(name+"正在卖票"+ticket--);
                }
              lock.unlock();
       }

    }
}

posted @ 2020-03-12 22:31  姚狗蛋  阅读(240)  评论(0编辑  收藏  举报