Java多线程不同步造成的安全问题解决方案

当多个线程调用和修改同一个数据时,有可能出现上一个线程的数据正在修改的时候,下一个线程也进来修改数据, 此时后进的线程可能会拿着过时的数据修改,产生数据的安全问题.

public class SecondThread {
    public static void main(String[] args) {
        //3.创建实现类的对象
        MyThread2 t2 = new MyThread2();
        //4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
        Thread s1 = new Thread(t2);
        Thread s2 = new Thread(t2);
        Thread s3 = new Thread(t2);
        s1.setName("窗口一");
        s2.setName("窗口二");
        s3.setName("窗口三");
        //5.通过Thread类的对象调用start()
        s1.start();
        s2.start();
        s3.start();

    }
}

/**
 * 1.创建一个实现了runnable接口的类
 * 2.实现类去实现runnable中的抽象方法run
 * 3.创建实现类的对象
 * 4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象
 * 5.通过Thread类的对象调用start()
 */
//1.创建一个实现了runnable接口的类
class MyThread2 implements Runnable {
    //2.实现类去实现runnable中的抽象方法run
    private int ticket = 100;

    @Override
    public void run() {
        while (true) {
            if (ticket > 0) {
                System.out.println(Thread.currentThread().getName() + "卖票了,号码为" + ticket);
                ticket--;
            } else {
                break;
            }
        }
    }
}

结果部分片段如下显示:

窗口一卖票了,号码为100
窗口一卖票了,号码为99
窗口一卖票了,号码为98
窗口一卖票了,号码为97
窗口一卖票了,号码为96
窗口二卖票了,号码为100

明显可以看出,一号窗口和二号窗口同时卖出了一张号码为100的票

面对这个问题,有两种解决方案选择:

一、同步代码块

synchronized(同步监视器){
	//需要被同步的代码
}

说明:

  1. 操作共享数据的代码,即为需要被同步的代码
  2. 共享数据:多个线程共同操作的变量,比如:ticket就是共享数据
  3. 同步监视器,俗称:锁。任何一个类的对象,都可以充当锁
    要求:多个线程必须共用同一把锁

好处:消除了因为代码不及时更新带来的影响。
坏处:因为中间同步代码块的原因导致synchronized内部的代码执行起来依然成为了单线程模式,操作同步代码时,只有一个线程参与,其他线程只能等待。

二、同步方法

如果操作共享数据的代码完整的生命在一个方法中,我们不妨将此方法声明为同步的。

同步方法操作很简单,只需要将需要同步的方法的修饰符写上synchronized即可

private synchronized void show(){
        //同步代码块
    }

此时,同步监视器为默认的this。

posted @ 2022-09-15 15:26  花粉回家  阅读(125)  评论(0)    收藏  举报