[JAVA笔记]-基础-多线程-解决同步问题的方式

多线程中解决同步问题的方式?

问题出现的原因:

  • 当多线程中访问了共享数据时,数据就会发生错误的情况!

解决问题的方式:

  • A:同步代码块方式
  • B:同步方法方式
  • C:Lock 锁方式

应用场景

我们通过多线程模拟售票窗口进行卖票。通过以上三种方式都可以解决同 步问题!

场景代码:

public class Test01 {
    public static void main(String[] args) {
        RunnableImpl r = new RunnableImpl();
        new Thread(r,"窗口1").start();
        new Thread(r,"窗口2").start();
    }
}

实现类

public class RunnableImpl implements Runnable{
    private int ticket = 100;
    @Override
    public void run(){
        while (true){
            if (ticket <= 0){
                break;
            }
            try {
                Thread.sleep(200);
                String name = Thread.currentThread().getName();
                System.out.println(name+"正在卖出第"+(100-ticket+1)+"张票,还剩余"+(--ticket)+"张");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 结果 image

可以发现结果出现了剩余票数为负数-1; 多卖票,最后卖到101张了; 可能重复卖票,同一张票被卖了两次的情况

解决方法一: 使用同步代码块方式

public class Test0 {
    public static void main(String[] args) {
        RunnableImpl1 r1 = new RunnableImpl1();
        new Thread(r1,"①窗口1").start();
        new Thread(r1,"①窗口2").start();
    }
}
public class RunnableImpl1 implements Runnable{
    private int ticket = 100;
    @Override
    public void run(){
        while (true){

            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (this){
                if (ticket <= 0){
                    break;
                }
                String name = Thread.currentThread().getName();
                System.out.println(name+"正在卖出第"+(100-ticket+1)+"张票,还剩余"+(--ticket)+"张");
            }
        }
    }
}
  • 结果: image

解决方法二: 使用同步方法方式

public class Test02 {
    public static void main(String[] args) {
        RunnableImpl2 r2 = new RunnableImpl2();
        new Thread(r2,"①窗口2").start();
        new Thread(r2,"①窗口2").start();
    }
}
public class RunnableImpl2 implements Runnable {
    private static int ticket = 100;
    @Override
    public void run() {
        //method();
        staticmethod();
    }
    //静态方法,锁对象是当前本类的类.class字节码对象
    private static synchronized void staticmethod() {
        while (true){
            if (ticket <= 0){
                break;
            }
            try {
                Thread.sleep(50);
                String name = Thread.currentThread().getName();
                System.out.println(name+"正在卖出第"+(100-ticket+1)+"张票,还剩余"+(--ticket)+"张");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    //非静态方法,锁对象是默认当前本类对象(this)
    public synchronized void method(){
        while (true){
            if (ticket <= 0){
                break;
            }
            try {
                Thread.sleep(50);
                String name = Thread.currentThread().getName();
                System.out.println(name+"正在卖出第"+(100-ticket+1)+"张票,还剩余"+(--ticket)+"张");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 结果: image

解决方法三: 使用lock锁方式

public class Test03 {
    public static void main(String[] args) {
        RunnableImpl3 r3 = new RunnableImpl3();
        new Thread(r3,"③窗口1").start();
        new Thread(r3,"③窗口2").start();
    }
}
public class RunnableImpl3 implements Runnable{
    private int ticket = 100;
    Lock l = new ReentrantLock();//更符合面向对象的思想

    @Override
    public void run(){
        while (true){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            l.lock();

            if (ticket <= 0){
                l.unlock();
                break;
            }
            try {
                Thread.sleep(100);
                String name = Thread.currentThread().getName();
                System.out.println(name+"正在卖出第"+(100-ticket+1)+"张票,还剩余"+(--ticket)+"张");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                l.unlock();
            }
        }
    }
}
  • 结果: image
更新时间:2019-10-18 14:30:13

本文由 Alicyu 创作,如果您觉得本文不错,请随意赞赏
采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
原文链接:https://www.alicyu.com/archives/threads
最后更新:2019-10-18 14:30:13

Your browser is out of date!

Update your browser to view this website correctly. Update my browser now

×