Java多线程中的线程安全问题

多个线程访问共享数据就会产生冲突的问题,以卖票为例,多个窗口卖同一批票就会出现重复卖的问题

  public static void main(String[] args) {
      Runnable runnable = new Runnable() {
          Integer tickets = 100;
          @Override
          public void run() {
              String name = Thread.currentThread().getName();
              while(tickets-- > 0) {
                  try {
                      Thread.sleep(1);
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
                  System.out.println(name + "正在卖票: " + tickets);
              }
          }
      };
      new Thread(runnable).start();
      new Thread(runnable).start();
      new Thread(runnable).start();
  }

解决方案一:使用同步机制,共享部分同步执行则不会出现重复操作问题

  1. synchronized关键字实现代码块同步
    public static void main(String[] args) {
        Object lock = new Object();
        Runnable runnable = new Runnable() {
            Integer tickets = 100;
    
            @Override
            public void run() {
                String name = Thread.currentThread().getName();
                while (true) {
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (lock) {
                        if (tickets <= 0) break;
                        System.out.println(name + "正在卖票: " + tickets);
                        tickets--;
                    }
                }
            }
        };
        new Thread(runnable).start();
        new Thread(runnable).start();
        new Thread(runnable).start();
    }
    
  2. synchronized同步方法实现同步机制
    static Integer tickets = 100;
    public static void main(String[] args) {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    sellTicked();
                    if (tickets <= 0) break;
                }
            }
        };
        new Thread(runnable).start();
        new Thread(runnable).start();
        new Thread(runnable).start();
    }
    
    synchronized private static void sellTicked() {
        if (tickets <= 0) return;
        String name = Thread.currentThread().getName();
        System.out.println(name + "正在卖票: " + tickets);
        tickets--;
    }
    

解决方案二:使用锁ReentrantLock

public class LockDemo {
    static Integer tickets = 100;
    public static void main(String[] args) {
        Runnable run = new Runnable() {
            ReentrantLock lock = new ReentrantLock();
            @Override
            public void run() {
                while(tickets > 0) {
                    try {
                        Thread.sleep(1);
                    }catch(Exception e) {

                    }
                    lock.lock();
                    sellTickets();
                    lock.unlock();
                }
            }
        };
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();
    }

    private static void sellTickets() {
        String threadName = Thread.currentThread().getName();
        if (tickets < 0) return;
        System.out.println(threadName + "正在卖第" + tickets + "张票");
        tickets--;
    }
}

Leave a Reply