2.1.5脏读

实现多个线程调用同一个方法时,为避免数据出现交叉的情况,使用synchronized关键字进行同步

虽然在赋值时进行了同步,但在取值时有可能出现一些意想不到的意外,这种情况就是脏读。发生脏读的情况是在读取实例变量时,此值已经被其他线程更改过了。

/**
 * @author wuyoushan
 * @date 2017/4/10.
 */
public class PublicVar {
    public String username="A";
    public String password="AA";

    synchronized public void setValue(String username,String password){
        try{
            this.username=username;
            Thread.sleep(5000);
            this.password=password;
            System.out.println("setValue method thread name="+
            Thread.currentThread().getName()+" username="+
            username+" password="+password);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    public void getValue(){
        System.out.println("getValue method thread name="+
                Thread.currentThread().getName()+" username="+
                username+" password="+password);
    }
}

/**
 * @author wuyoushan
 * @date 2017/4/4.
 */
public class ThreadA extends Thread{

    private PublicVar publicVar;

    public ThreadA(PublicVar publicVar){
        super();
        this.publicVar=publicVar;
    }

    @Override
    public void run() {
        super.run();
        publicVar.setValue("B","BB");
    }
}

/**
 * @author wuyoushan
 * @date 2017/3/14.
 */
public class Test {
    public static void main(String[] args) {
       try{
           PublicVar publicVar=new PublicVar();
           ThreadA thread=new ThreadA(publicVar);
           thread.start();
            Thread.sleep(200);
           publicVar.getValue();
       }catch (InterruptedException e){
           e.printStackTrace();
       }
    }
}

程序的运行结果为:

getValue method thread name=main username=B password=AA
setValue method thread name=Thread-0 username=B password=BB

出现脏读是因为public void getValue()方法并不是同步的,所以可以在任意时候进行调用。解决方法当然就是加上同步synchronized关键字,代码如下:

/**
 * @author wuyoushan
 * @date 2017/4/10.
 */
public class PublicVar {
    public String username="A";
    public String password="AA";

    synchronized public void setValue(String username,String password){
        try{
            this.username=username;
            Thread.sleep(5000);
            this.password=password;
            System.out.println("setValue method thread name="+
            Thread.currentThread().getName()+" username="+
            username+" password="+password);
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    synchronized public void getValue(){
        System.out.println("getValue method thread name="+
                Thread.currentThread().getName()+" username="+
                username+" password="+password);
    }
}

程序的运行结果为:

setValue method thread name=Thread-0 username=B password=BB
getValue method thread name=main username=B password=BB

可见,方法setValue()和getValue()被依次执行。通过这个案例不仅要知道脏读是通过synchronized关键字解决的,还要知道如下内容:

当A线程调用anyObject对象加入synchronized关键字的X方法时,A线程就获得了X方法的锁,更准确的讲,是获取了对象的锁,所以其他线程必须等A线程执行完毕才可以调用X方法,但B线程可以随意调用其他的非synchronized同步方法

当A线程调用anyObject对象加入synchronized关键字的X方法时,A线程就获得了X方法的所在对象的锁,所以其他线程必须等A线程执行完毕才可以调用X方法,而B线程如果调用声明了synchronized关键字的非X方法时,必须等A线程将X方法执行完,也就是释放对象锁后才可以调用。这时A线程已经执行了一个完整的任务,也就是说username和password这两个实例变量已经同时被赋值,不存在脏读的基本环境

摘选自 java多线程核心编程技术-2.1.5

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • Java8张图 11、字符串不变性 12、equals()方法、hashCode()方法的区别 13、...
    Miley_MOJIE阅读 3,969评论 0 11
  • 本文出自 Eddy Wiki ,转载请注明出处:http://eddy.wiki/interview-java.h...
    eddy_wiki阅读 2,340评论 0 14
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 35,192评论 18 399
  • 简介 本次主要介绍java多线程中的同步,也就是如何在java语言中写出线程安全的程序。如何在java语言中解决非...
    小人物灌篮阅读 565评论 0 1
  • 早晨六点多,天还未大亮。在冬日朦胧的氤氲中,我带着年过花甲的父亲匆匆赶往医院做检查。 坐在公交车上,我想起父亲说的...
    宝昱阅读 310评论 0 2

友情链接更多精彩内容