java对象锁有两种:对象锁、类锁。
对象锁:在非静态方法上加锁。声明了一个对象锁。类锁:在静态方法上加锁,声明了一个类锁。
经过大量的实验总结出以下结论:
1、想要保证能够锁住对象,需要在对应的的普通方法上加上synchronized关键字。
2、想要保证能够锁住对象,需要在对应的的普通方法上加上synchronized关键字。
3、非静态函数用关键字synchronized不会对普通方法有影响。
4、普通函数用关键字synchronized不会对静态方法有影响。
然后我们来做一个实验:
1、我们先声明一个类对象,
2、声明了两个普通方法,一个method1用synchronized关键字修饰,另一个method2没有锁(没有用synchronized修饰)
3、两个函数都调用另一个普通函数method3,函数method让对象的属性加一。循环一万次。
4、有两个线程分别执行method1和method2。那么执行结果是什么呢?
线程类:
package Test;
public class Syn extends Thread{
int i;
private TestSyn syn;
public Syn(int i ,TestSyn syn) {
this.i=i;
this.syn=syn;
}
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(i%2==0) {
syn.method1(syn);
}
else {
syn.method2(syn);
}
}
}
测试类:
package Test;
public class TestSyn {
private int i;
public TestSyn(int i) {
this.i=i;
}
public synchronized void method1(TestSyn aSyn) {
System.out.println("1");
method3(aSyn);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("变化的i"+aSyn.i);
}
public void method2(TestSyn aSyn) {
System.out.println("2");
method3(aSyn);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("变化的i"+aSyn.i);
}
public void method3(TestSyn aSyn) {
for(int i=0;i<10000;i++) {
aSyn.i++;
}
}
public static void main(String[] args) {
Syn []a = new Syn[2];
TestSyn aSyn=new TestSyn(0);
a[0]=new Syn(1,aSyn);
a[1]=new Syn(2,aSyn);
a[1].start();
a[0].start();
}
}
理论上是20000,实际上会少很多,所以这种方式是线程不安全的。
所以如果想让两个函数互斥的访问某些资源,在对应的函数访问的时候都要加上锁。这样才能保证数据的正确性。
在此我向大家推荐一个架构学习交流群。交流学习群号:938837867 暗号:555 里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化、分布式架构等这些成为架构师必备