由于同一进程中线程间的数据资源是共享的,因此常常会导致资源数据做出不被期望的更改,这时,便需要引入锁,来使得数据同步。
public class SynchronizedDemo {
private int a ;
public SynchronizedDemo(){
this.a=1;
}
public void setA(int a){
this.a=a;
}
private void calculate(){
this.a = a*2;
}
public void getA(){
System.out.println("Thread:"+Thread.currentThread().getId()+",a="+a);
}
public void print(){
calculate();
getA();
}
public static void main(String args[]){
final SynchronizedDemo demo= new SynchronizedDemo();
for(int i=0;i<10;i++)
{
new Thread(){
@Override
public void run() {
// TODO Auto-generated method stub
demo.print();
}
}.start();
}
}
}
上面的code是没有加上锁,这时输出结果为
Thread:8,a=2
Thread:10,a=4
Thread:9,a=8
Thread:11,a=16
Thread:12,a=32
Thread:13,a=64
Thread:14,a=128
Thread:15,a=512
Thread:16,a=512
Thread:17,a=1024
可以看到,输出结果中出现了两个512。原因便是,在其中一个线程在读取到a值为128并对其做出修改之前,另一个线程也读取了a值128。
这边产生了冲突,导致了数据的不一致性。
解决的方法其实不唯一,这里介绍使用锁来进行保障。
java中提供了synchronized 关键字,来限制只有一个线程可以访问该代码块或者方法,这个关键字可以使用的方式有两种。
public synchronized void print(){
calculate();
getA();
}
public void print(){
synchronized(this){
calculate();
getA();
}
}
只有前一个线程访问结束后,下一个线程才能继续访问。
Thread:9,a=2
Thread:11,a=4
Thread:14,a=8
Thread:12,a=16
Thread:8,a=32
Thread:10,a=64
Thread:13,a=128
Thread:15,a=256
Thread:16,a=512
Thread:17,a=1024
多次试验后,可以看到得到的结果是无误的。
同时,在JDK1.5版本以后,增加了concurrent包,专门用于处理线程。
private Lock lock = new ReentrantLock();
public void print(){
lock.lock();
calculate();
getA();
lock.unlock();
}
ReentrantLock便是其中实现一个锁。
相对于synchronized,听说ReentrantLock更为高效些,还未作出验证,下次抽空一定得验证下,再编辑修正。
本文如果有错误的地方,请及时指正,谢谢
下一章:ReentrantLock的源码分析