赞
踩
“非线程安全”其实会在多个线程对同一个对象中的实例变量进行并发访问时发生,产生的后果就是“脏读”,也就是取到的数据其实是被更改过的。
1**、方法内的变量为线程安全的**
方法内部的私有变量,则不存在“非线程安全”的问题,所得结果也就是“线程安全”的。
2、实例变量非线程安全
如果多个线程共同访问一个对象中的实例变量,则有可能出现“非线程安全”问题。
用线程访问的对象中如果有多个实例变量,则运行的结果有可能出现交叉的情况。
如果对象仅有一个实例变量,则有可能出现覆盖的情况。
1、对象实例
public class HasSelfPrivateNum {
//实例变量
private int num=0;
public void addI(String userName){
try{
if(userName.equals("a")){
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();
}
}
}
为了避免“非线程安全”问题,在方法前加关键字 synchronized.
synchronized public void addI(String userName)
或者
public synchronized void addI(String userName)
在多个线程访问同一个对象中的同步方法时一定是线程安全的。
同步是synchronized, 异步是 asynchronized。
关键字synchronized取得的锁都是对象锁,而不是把一段代码或方法(函数)当做锁。哪个线程先执行带synchronized关键字的方法,哪个线程就持有该方法所属对象的锁***Lock,那么其他线程只能是等待状态,前提是多个线程访问的是同一个对象*。
但是如果多个线程访问多个对象(不同的对象),则JVM会创建多个锁。
public class Run {
public static void main(String[] args) {
//两个不同的对象
HasSelfPrivateNum has1=new HasSelfPrivateNum();
HasSelfPrivateNum has2=new HasSelfPrivateNum();
//两个线程
CountOperate c1=new CountOperate(has1);
CountOperate c2=new CountOperate(has2);
//启动之后,结果是异步执行,与启动顺序无关
c1.start();
c2.start();
try{
Thread.sleep(5000);
}catch (InterruptedException e){
}
}
}
调用关键字synchronized声明的方法一定是排队运行的(同步的)。只有共享资源的读写访问才需要同步化,如果不是共享资源,根本没有同步的必要。
1、(两个线程分别访问同一个对象的 同步方法和 非同步方法)A线程先持有object对象的Lock锁,B线程可以以异步的方式调用同一个object对象中的 非synchronized类型的方法。(非线程方法的调用不受影响)
2、(两个线程分别访问同一个对象的 两个不同的 同步方法)A线程先持有object对象的Lock锁,B线程如果调用同一个对象的另一个同步方法则需要等待,也就是同步。
三、脏读—一个线程在读取数据,另一个线程在设置数据(同一个对象中,一个是同步方法,一个是非同步)。
发生脏读的情况是在读取实例变量时,此值已经被其他线程更改过了。(对于修改和读取的方法都设置同步synchronized)
四、synchronized锁重入—自己可以再次获得自己的内部锁
在使用synchronized时,当一个线程得到一个对象锁后,(只要该线程还没有释放这个对象锁,)再次请求此对象锁时是可以再次得到该对象的锁的。(也就是同步方法可以调用同一个对象的另一个同步方法)
public class HasSelfPrivateNum {
public synchronized void addI(String userName){
//同一个线程中,同一个对象的同步方法
//可以获得该对象锁Lock
addA(userName);
}
public synchronized void addA(String userName){
}
}
可重入锁也支持在父子类继承的环境中。当存在父子类继承关系时,子类是完全可以通过“可重入锁”调用父类的同步方法。
public class SubHasSelfPrivateNum extends HasSelfPrivateNum {
public synchronized void addC(String userName){
//调用父类的同步方法,也可以获得对象锁
this.addI(userName);
}
}
当一个线程执行的代码出现异常时,其所持有的锁会自动释放。
五、同步不具有继承性 —同步不可以继承
//父类
public class HasSelfPrivateNum {
//父类的同步方法
public synchronized void addI(String userName){
}
}
//子类
public class SubHasSelfPrivateNum extends HasSelfPrivateNum {
//同名方法,但是不是同步的
public void addI(String userName){
//调用父类的同步方法
super.addI(userName);
}
}
多个线程调用子类的方法是异步调用的。但是调用父类的方法,则是同步的
思考:如果一开始就调用同步的方法,那么在该同步方法中存在调用其他方法(无论是否同步),都应该是同步的。
//非同步的对象
public class NoSysnTest {
public void play(){
System.out.println("sleep begin threadName="+Thread.currentThread().getName()+" time="+System.currentTimeMillis());
try{
Thread.sleep(5000);
System.out.println("sleep end threadName="+Thread.currentThread().getName()+" time="+System.currentTimeMillis());
}catch (InterruptedException e){
}
}
}
//线程
public class CountOperate extends Thread {
private HasSelfPrivateNum numRef;
private NoSysnTest noSysnTest;
public CountOperate(HasSelfPrivateNum numRef,NoSysnTest noSysnTest){
this.numRef=numRef;
this.noSysnTest=noSysnTest;
}
public void run(){
//调用对象的同步方法
numRef.addI("a",noSysnTest);
}
}
//同步的对象
public class HasSelfPrivateNum {
public synchronized void addI(String userName,NoSysnTest noSysnTest){
//调用非同步的方法
noSysnTest.play();
}
}
//执行
public class Run {
public static void main(String[] args) {
//两个不同的对象
HasSelfPrivateNum has1=new HasSelfPrivateNum();
NoSysnTest noSysnTest=new NoSysnTest();
//两个线程
CountOperate c1=new CountOperate(has1,noSysnTest);
c1.setName("A");
CountOperate c2=new CountOperate(has1,noSysnTest);
c2.setName("B");
//启动之后,结果是异步执行,与启动顺序无关
c1.start();
c2.start();
noSysnTest.play();
}
}
//结果
//main线程并不是同步的,而是异步的
//A、B线程是同步的,
sleep begin threadName=main time=1520412948959
sleep begin threadName=B time=1520412948969
sleep end threadName=main time=1520412953960
sleep end threadName=B time=1520412953969
sleep begin threadName=A time=1520412953969
sleep end threadName=A time=1520412958969
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。