对象及变量的并发访问
2.1 synchronized同步方法
首先在这里说明两个概念:线程安全和非线程安全
线程安全:就是获取的实例变量的值经过同步处理不会出现脏读的现象。
非线程安全:就是多个线程对同一个对象中的实例变量进行并发访问时发生脏读的,即取到的数据其实是被更改过的。
2.1.1 实例变量非线程安全
下面我们用代码来说明一下非线程安全,HasSelfPrivateNum.java
代码如下:
public class HasSelfPrivateNum {
private int num = 0;
public void addI(String username) {
try {
if (("a").equals(username)) {
num = 100;
System.out.println("a set over");
Thread.sleep(2000);
} else {
num = 200;
System.out.println("b set over");
}
System.out.println(username + " num= " + num);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
自定义线程类 MyThread1.java
, MyThread2.java
代码如下:
public class MyThread1 extends Thread{
private HasSelfPrivateNum hasSelfPrivateNum;
public MyThread1(HasSelfPrivateNum hasSelfPrivateNum){
this.hasSelfPrivateNum=hasSelfPrivateNum;
}
@Override
public void run() {
hasSelfPrivateNum.addI("a");
}
}
public class MyThread2 extends Thread{
private HasSelfPrivateNum hasSelfPrivateNum;
public MyThread2 (HasSelfPrivateNum hasSelfPrivateNum){
this.hasSelfPrivateNum=hasSelfPrivateNum;
}
@Override
public void run() {
hasSelfPrivateNum.addI("b");
}
}
创建运行类 Test.java
,代码如下:
public class Test {
public static void main(String[] args) {
HasSelfPrivateNum hasSelfPrivateNum=new HasSelfPrivateNum();
MyThread1 myThread1=new MyThread1(hasSelfPrivateNum);
myThread1.start();
MyThread2 myThread2=new MyThread2(hasSelfPrivateNum);
myThread2.start();
}
}
代码运行运行结果:
a set over
b set over
b num= 200
a num= 200
两个线程同时访问一个没有同步的方法,如果两个线程同时操作业务对象中的实例变量,则会出现 “非线程安全”的问题,那我们如何解决这个问题,只需要在 public void addI(String username)
方法前面加上关键字synchronized
即可 ,更改后方法的代码如下:
public synchronized void addI(String username)
再次运行程序结果如下:
a set over
a num= 100
b set over
b num= 200
所以得出结论,两个线程访问同一个对象中的同步方法时一定是线程安全的。
2.1.2 多个对象多个锁
其他类的代码不变,修改运行类 Test.java
,代码如下:
public class Test {
pu