Java -- 线程的安全问题

·  阅读 20

「这是我参与11月更文挑战的第17天,活动详情查看:2021最后一次更文挑战

线程的安全问题:

案例:卖票

截屏2021-11-08 上午10.48.48.png

public class Ticket implements Runnable{
    // 票的数量
    private int ticket = 100;

    @Override
    public void run() {
        while (true){
            if (ticket == 0){
                break;
            }else {
                ticket--;
                System.out.println(Thread.currentThread().getName() + "在卖票" + ticket + "张票");
            }
        }
    }
}
复制代码
public class Demo {
    public static void main(String[] args) {

        Ticket ticket1 = new Ticket();

        Thread t1 = new Thread(ticket1);
        Thread t2 = new Thread(ticket1);
        Thread t3 = new Thread(ticket1);

        t1.setName("窗口一");
        t2.setName("窗口二");
        t3.setName("窗口三");

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

    }
}
复制代码

截屏2021-11-08 上午11.03.43.png

public class Ticket implements Runnable{
    // 票的数量
    private int ticket = 100;

    @Override
    public void run() {
        while (true){
            if (ticket == 0){
                break;
            }else {
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                ticket--;
                System.out.println(Thread.currentThread().getName() + "在卖票" + ticket + "张票");
            }
        }
    }
}
复制代码

截屏2021-11-08 上午11.06.26.png

卖票案例数据安全问题的解决:

为什么出现问题?(这也是我们判断多线程程序是否会有数据安全问题的标准)

多线程操作共享数据

如何解决多线程安全问题呢?

基本思想:让程序没有安全问题的环境。

怎么实现呢?

把多条语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可。

Java提供了同步代码块的方式来解决。

同步代码块:

截屏2021-11-08 上午11.12.57.png

public class Ticket implements Runnable{
    // 票的数量
    private int ticket = 100;
    private Object obj = new Object();

    @Override
    public void run() {
        while (true){
            synchronized (obj){ // 多个线程必须使用同一把锁
                if (ticket <= 0){
                    break;
                }else {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    ticket--;
                    System.out.println(Thread.currentThread().getName() + "在卖票" + ticket + "张票");
                }
            }
        }
    }
}
复制代码

以下代码 或出现负数票。锁有问题

public class MyThread extends Thread{
    private static int tiketCount = 100;

    @Override
    public void run() {
        while (true){
            synchronized (this){
                if (tiketCount <= 0){
                    break;
                }else {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    tiketCount --;
                    System.out.println(Thread.currentThread().getName() + "在卖票,还剩下" + tiketCount + "张票");
                }
            }
        }
    }
}
复制代码

public class Demo {
    public static void main(String[] args) {
        MyThread t1 = new MyThread();
        MyThread t2 = new MyThread();

        t1.setName("窗口1");
        t2.setName("窗口2");

        t1.start();
        t2.start();

    }
}
复制代码

一定要保证 锁对象是唯一的。

public class MyThread extends Thread{
    private static int tiketCount = 100;
    private static Object obj = new Object();
    
    @Override
    public void run() {
        while (true){
            synchronized (obj){
                if (tiketCount <= 0){
                    break;
                }else {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    tiketCount --;
                    System.out.println(Thread.currentThread().getName() + "在卖票,还剩下" + tiketCount + "张票");
                }
            }
        }
    }
}
复制代码

同步方法:

截屏2021-11-08 上午11.27.49.png

public class MyThreadRunable implements Runnable {
    private static int ticketCount = 100;

    @Override
    public void run() {
        while (true){
            if ("窗口1".equals(Thread.currentThread().getName())){
                // 同步方法
                boolean result = synchronizedMethod();
                if (result){
                    break;
                }
            }

            if ("窗口2".equals(Thread.currentThread().getName())){
                // 同步代码块
                synchronized (this){
                    if (ticketCount == 0){
                        break;
                    }else {
                        try {
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }

                        ticketCount--;
                        System.out.println(Thread.currentThread().getName() + "在卖票" + ticketCount + "张票");
                    }
                }
            }
        }
    }

    private synchronized boolean synchronizedMethod(){
        if (ticketCount == 0){
            return true;
        }else {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            ticketCount--;
            System.out.println(Thread.currentThread().getName() + "在卖票" + ticketCount + "张票");

            return false;
        }
    }
}
复制代码
public class Demo {
    public static void main(String[] args) {
        MyRunnable mr = new MyRunnable();

        Thread t1 = new Thread(mr);
        Thread t2 = new Thread(mr);

        t1.setName("窗口1");
        t2.setName("窗口2");

        t1.start();
        t2.start();

    }
}
复制代码

截屏2021-11-08 上午11.37.52.png

截屏2021-11-08 上午11.38.20.png

Lock 锁

截屏2021-11-08 上午11.39.19.png


public class Ticket implements Runnable {
    // 票的数量
    private int ticket = 100;
    private ReentrantLock lock = new ReentrantLock();


    @Override
    public void run() {
        while (true) {
            try {
                lock.lock();
                if (ticket <= 0) {
                    break;
                } else {
                    Thread.sleep(100);
                    ticket--;
                    System.out.println(Thread.currentThread().getName() + "在卖票" + ticket + "张票");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
}
复制代码

死锁:

截屏2021-11-08 上午11.44.29.png

截屏2021-11-08 上午11.45.54.png

public class Demo {
    public static void main(String[] args) {
        Object objA = new Object();
        Object objB = new Object();

        new Thread(()->{
            while (true){
                synchronized (objA){
                    synchronized (objB){
                        System.out.println("小康同学在走路");
                    }
                }
            }
        }).start();

        new Thread(()->{
            while (true){
                synchronized (objB){
                    synchronized (objA){
                        System.out.println("小微同学在走路");
                    }
                }
            }
        }).start();
    }
}
复制代码
分类:
后端
标签: