Java多线程5:synchronized锁机制

时间:2022-04-20 13:05:40

一、脏读

  在多线程中,有时会出现多个线程对同一个对象的变量进行并发访问的情形,如果不做正确的同步处理,那么产生的后果就是“脏读”,也就是获取到的数据其实是被修改过的。

二、多线程线程安全实例

  举例:两个线程分别获取不同的userName对应的num值。

  ThreadSynch类,不同的userName对应不同的num值,“zhangsan”对应的num值是100,其他的userName对应的num值是200

public class ThreadSynch {

    private int num;

    public void getNumByUserName(String userName){
        if("zhangsan".equals(userName)){
            try {
                num = 100;
                System.out.println("zhangsan getNum over");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }else{
            num = 200;
            System.out.println("someBody else getNum over");
        }
        System.out.println(userName + "======" + num);
    }

}

  定义两个线程去获取不同的userName对应的num值,线程1获取“zhangsan”对应的num值

public class Thread01 extends Thread{
    private ThreadSynch threadSynch;

    public Thread01(ThreadSynch threadSynch) {
        this.threadSynch = threadSynch;
    }

    @Override
    public void run() {
        threadSynch.getNumByUserName("zhangsan");
    }
}

  线程2获取“lisi”对应的num值

public class Thread02 extends Thread{
    private ThreadSynch threadSynch;

    public Thread02(ThreadSynch threadSynch) {
        this.threadSynch = threadSynch;
    }

    @Override
    public void run() {
        threadSynch.getNumByUserName("lisi");
    }
}

  测试,通过上面两个线程去获取对应的num值

public class Test {
    public static void main(String[] args) {
        ThreadSynch threadSynch = new ThreadSynch();
        Thread01 thread01 = new Thread01(threadSynch);
        Thread02 thread02 = new Thread02(threadSynch);
        thread01.start();
        thread02.start();
    }
}

  按说,结果应该是:“zhangsan”对应的num值是100,“lisi”对应的num值是200,看一下控制台的打印,“zhangsan”和“lisi”的num值都是200

zhangsan getNum over
someBody else getNum over
lisi======200
zhangsan======200

  其实就算是把Thread.sleep(1000)去掉的话,运行多次的话也会捕捉到线程安全的问题

zhangsan getNum over
zhangsan======200
someBody else getNum over
lisi======200

  分析一下上述的线程安全问题是怎么产生的:

  1、thread01先运行,去获取“zhangsan”对应的num值,此时num值已经被赋值为100了,然后开始睡眠1秒,控制台显示“zhangsan getNum over”

  2、在thread01睡眠的时候,thread02开始运行或是运行结束了,此时num值已经由100改成了200,控制台显示“someBody else getNum over    lisi======200”

  3、thread01睡眠结束,但由于thread01和thread02操作的是同一个对象的num属性,所以此时num值已经由100变成了200,控制套显示“zhangsan======200”

  产生问题的原因找到了,解决就很简单了。thread01操作threadSynch对象的getNumByUserName()方法的时候,在其结束之前不要让thread02进入该方法执行,即给getNumByUserName()方法加一个同步锁。

public class ThreadSynch {

    private int num;

    public synchronized void getNumByUserName(String userName){
        if("zhangsan".equals(userName)){
            num = 100;
            System.out.println("zhangsan getNum over");
        }else{
            num = 200;
            System.out.println("someBody else getNum over");
        }
        System.out.println(userName + "======" + num);
    }

}

  结果:

zhangsan getNum over
zhangsan======100
someBody else getNum over
lisi======200

三、

 

 

 

 

https://blog.csdn.net/xiao__gui/article/details/8188833#commentBox