1、synchronized同步方法主要是用来解决非线程安全的问题。
非线程安全问题主要存在与“实例变量”中,如果是方法内部的私有变量,则不存在“非线程安全”问题,所得的结果也就是线程安全的。
public class HasSelfPrivateNum{
public void addI(String username){
try{
int num = 0;
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(InterruptedExcepiton e){
e.printStackTrace();
}
}
//ThreadA.java
public class ThreadA extends Thread{
private HasSelfPrivateNum numRef;
public ThreadA(HasSelfPrivateNum numRef){
super();
this.numRef = numRef;
}
@Override
public void run(){
super.run();
numRef.addI("a");
}
}
//ThreadB.java
public class ThreadB extends Thread{
private HasSelfPrivateNum numRef;
public ThreadB(HasSelfPrivateNum numRef){
super();
this.numRef = numRef;
}
@Override
public void run(){
super.run();
numRef.addI("b");
}
}
//Run.java
public calss Run{
public static void main(String[] args){
HasSelfPrivateNum numRef = new HasSelfPrivateNum();
ThreadA athread = new ThreadA(numRef);
athread.start();
ThreadB bthread = new ThreadB(numRef);
bthread.start();
}
}
//运行结果为:
//a set over
//b set over
//a num = 100
//b num = 200
2、实例变量非线程安全问题
如果对象仅有一个实例变量,多个线程在操作此对象的过程中,会出现覆盖的情况。也就是数据的交叉。解决这类问题的关键是在操作对象的方法上,添加synchronized关键字,使操作对象的方法成为同步方法。两个线程在访问同一个对象中的同步方法时,一定是线程安全的。
3、多个对象的多个锁
两个线程分别访问同一个类的不同实例的相同或名称的同步方法,结果却是异步的。因为同一个类的不同实例,是不同的,而synchronized方法获得的锁是对象锁,因为对象不一样,所以获得的锁也是不一样的,因此一个对象获得一个实例的锁,并不会妨碍另一个线程获得两一个实例方法中的锁。
关键字synchronized取得的都是对象锁,而不是一段代码或方法当作锁。在大前提下:多个线程访问同一个对象的时候,哪个线程先执行带synchronized关键字的方法,哪个线程就持有该方法所属对象的锁,那么其他线程只能呈等待状态。另外需要牢牢记住:只有共享资源的读写访问才需要同步化,如果不是共享,或者不同线程操作的是不同对象,那么就没有同步的必要。