脏读(菜鸟玩线程)

脏读

脏读一定会出现在操作实例变量的情况下,这就是不同线程”争抢“实例变量的结果。

脏读示例

定义共享变量实例类

package com.chapter02.dirtyRead;

public class PublicVar {
    public String username = "A";
    public String password = "AA";

    //添加synchronized
    synchronized public void setVaule(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);
    }
}

自定义线程类

package com.chapter02.dirtyRead;
public class ThreadA extends Thread {
    private PublicVar publicVar;

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

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

启动类

package com.chapter02.dirtyRead;

public class TestRun {
    public static void main(String[] args) {
        try {
            PublicVar publicVar = new PublicVar();
            ThreadA threadA = new ThreadA(publicVar);
            threadA.start();
            Thread.sleep(2000); //打印结果受此值的影响
            publicVar.getValue();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

执行结果

//出现脏读
getValue method , thread name= main, username = B, password = AA
setValue method , thread name= Thread-0, username = B, password = BB

总结

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

防止脏读示例

修改

修改上面“定义共享变量实例类PublicVar ”中的getValue()方法,增加synchronized关键字,如下:

package com.chapter02.dirtyRead;

public class PublicVar {
    public String username = "A";
    public String password = "AA";

    //添加synchronized
    synchronized public void setVaule(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
    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

总结

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值