多线程出现脏读以及解决方法(使用synchronized)

2018-01-13 11:11:27来源:oschina作者:IT-Mamba人点击

分享

使用多线程出现脏读,得到的结果不是设计时想要的怎么办呢? 直接看示例:


出现脏读的程序

DealThread.java


public class DealThread implements Runnable {
private String username;
public void setUsername(String username) {
this.username = username;
}
@Override
public void run() {
System.out.println(" in run " + Thread.currentThread().getName() + "" + username);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(" out run " + Thread.currentThread().getName() + "" + username);
}
}

Run2_2.java


public class Run2_2 {
public static void main(String[] args) {
DealThread d1 = new DealThread();
d1.setUsername("aa");
Thread t1 = new Thread(d1,"A");
t1.start();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
d1.setUsername("bb");
Thread t2 = new Thread(d1,"B");
t2.start();
}
}

输出结果是:


in run A aa in run B bb out run A bb out run B bb


加同步锁和使用不同的DealThread对象都能解决这个问题,但是同步锁加得不对还是不能解决问题的,比如修改DealThread.java


修改方法1:(不能解决)
public class DealThread implements Runnable {
private String username;
public void setUsername(String username) {
this.username = username;
}
@Override
public void run() {
synchronized (this) {
System.out.println(" in run " + Thread.currentThread().getName() + "" + username);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(" out run " + Thread.currentThread().getName() + "" + username);
}
}
}

输出结果为:


in run A aa out run A bb in run B bb out run B bb


还是没达到效果,这样已经做对一半了,再给 setUsername加上synchronized就可以了


修改方法2:
public class DealThread implements Runnable {
private String username;
public synchronized void setUsername(String username) {
this.username = username;
}
@Override
public void run() {
synchronized (this) {
System.out.println(" in run " + Thread.currentThread().getName() + "" + username);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(" out run " + Thread.currentThread().getName() + "" + username);
}
}
}

这样输出结果就为:


in run A aa out run A aa in run B bb out run B bb


另外一种改法就是修改Run2_2.java 为每个线程分配一个DealThread对象,这样就不会出现脏读


修改方法3:
public class Run2_2 {
public static void main(String[] args) {
DealThread d1 = new DealThread();
d1.setUsername("aa");
Thread t1 = new Thread(d1,"A");
t1.start();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
DealThread d2 = new DealThread();
d2.setUsername("bb");
Thread t2 = new Thread(d2,"B");
t2.start();
}
}

这样的话两个线程会异步打印出各自的内容,互不影响,效率也会快一点,因为不用等上一个线程释放锁。


结合前面两篇关于多线程synchronized还可以这样改(个人觉得这样比较符合实际开发)


修改方法4:

新建merch.java


public class merch {
private String username;
public String getUsername() {
return username;
}
public synchronized void setUsername(String username) {
this.username = username;
}
}

修改DealThread.java


public class DealThread implements Runnable {
private merch merchA;
DealThread (merch merchA) {
this.merchA = merchA;
}
@Override
public void run() {
synchronized (merchA) {
System.out.println(" in run " + Thread.currentThread().getName() + "" + merchA.getUsername());
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(" out run " + Thread.currentThread().getName() + "" + merchA.getUsername());
}
}
}

修改Run2_2.java


public class Run2_2 {
public static void main(String[] args) {
merch merchA = new merch();
merchA.setUsername("aa");
DealThread d1 = new DealThread(merchA);
Thread t1 = new Thread(d1,"A");
t1.start();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
merchA.setUsername("bb");
Thread t2 = new Thread(d1,"B");
t2.start();
}
}

这样运行结果还是: in run A aa out run A aa in run B bb out run B bb


原理还是给 setUsername 和 输出的代码块加锁

个人即兴写的程序和临时想到的解决方法,如果更优的解决方法请留下高见,谢谢。

最新文章

123

最新摄影

闪念基因

微信扫一扫

第七城市微信公众平台