synchronized的使用
一.同步的实现:利用锁对象来达到同步的效果,如下面的lock
//同步代码块
synchronized (lock){
for(int i=0;i<100;i++)
System.out.println("第"+i+"次执行了方法");
}
二.当线程执行到这里时,就会使用这个锁对象,此时其他线程来到同步代码块,由于锁对象已经被使用了,就会进行等待,这样就达到了同步的效果,当第一个线程完成同步代码块,就会释放锁对象,此时其他线程才有机会进入
三.锁对象有三种:
- 自定义对象
- 当前类的this对象
- 类的Class对象,每一个类可以new多个对象,但是对应的Class对象只有一个
MyTest myTest1=new MyTest();
MyTest myTest2=new MyTest();
//结果为false,说明对象不相同
System.out.println(myTest1==myTest2);
Class myTestClass1=MyTest.class;
Class myTestClass2=MyTest.class;
//结果为true,说明是同一个
System.out.println(myTestClass1==myTestClass2);
//自定义对象,obj就是自定义的
static class SynchronizedTest{
Object obj=new Object();
public void print(String name){
synchronized (obj){
for(int i=0;i<100;i++)
System.out.println(name+"第"+i+"次执行了方法");
}
}
}
//当前类的this对象
static class SynchronizedTest{
public void print(String name){
synchronized (this){
for(int i=0;i<100;i++)
System.out.println(name+"第"+i+"次执行了方法");
}
}
}
//类的class对象,用其他类的Class对象也可以
static class SynchronizedTest{
public void print(String name){
synchronized (SynchronizedTest.class){
for(int i=0;i<100;i++)
System.out.println(name+"第"+i+"次执行了方法");
}
}
}
四.进行测试
推论:按第二步说的,线程进入就对锁对象进行使用,此时其他线程就无法进入,带着这个思路往下看
//这里不进行更改
static class MyThread extends Thread{
SynchronizedTest synchronizedTest;
public MyThread(String name,SynchronizedTest synchronizedTest) {
super(name);
this.synchronizedTest=synchronizedTest;
}
public void run(){
synchronizedTest.print(super.getName());
}
}
//第一次测试,自定义锁对象
public static void main(String[] agrs){
SynchronizedTest synchronizedTest1=new SynchronizedTest();
MyThread thread1=new MyThread("小明",synchronizedTest1);
MyThread thread2=new MyThread("小王",synchronizedTest1);
thread1.start();
thread2.start();
}
//
static class SynchronizedTest{
Object obj=new Object()
public void print(String name){
synchronized (obj){
for(int i=0;i<100;i++)
System.out.println(name+"第"+i+"次执行了方法");
}
}
}
结果:小明先执行完,小王才可以开始
小明先拿到锁对象obj,执行完整个循环后退出了代码块,此时小王才可以开始
//第1-1测试(后面加的...)
//自定义锁对象,不同的是new了俩个SynchronizedTest对象
public static void main(String[] agrs){
SynchronizedTest synchronizedTest1=new SynchronizedTest();
SynchronizedTest synchronizedTest2=new SynchronizedTest();
MyThread thread1=new MyThread("小明",synchronizedTest1);
MyThread thread2=new MyThread("小王",synchronizedTest2);
thread1.start();
thread2.start();
}
//
static class SynchronizedTest{
Object obj=new Object()
public void print(String name){
synchronized (obj){
for(int i=0;i<100;i++)
System.out.println(name+"第"+i+"次执行了方法");
}
}
}
结果:小明没有执行完,小王就执行了
不同之处:第二次new了俩个SynchronizedTest对象,此时里面obj也会不相同
//第二次测试,Class锁对象
public static void main(String[] agrs){
SynchronizedTest synchronizedTest1=new SynchronizedTest();
MyThread thread1=new MyThread("小明",synchronizedTest1);
MyThread thread2=new MyThread("小王",synchronizedTest1);
thread1.start();
thread2.start();
}
static class SynchronizedTest{
public void print(String name){
synchronized (SynchronizedTest.class){
for(int i=0;i<100;i++)
System.out.println(name+"第"+i+"次执行了方法");
}
}
}
//第三次测试,Class锁对象,不同的是,new了俩个SynchronizedTest对象
public static void main(String[] agrs){
SynchronizedTest synchronizedTest1=new SynchronizedTest();
SynchronizedTest synchronizedTest2=new SynchronizedTest();
MyThread thread1=new MyThread("小明",synchronizedTest1);
MyThread thread2=new MyThread("小王",synchronizedTest2);
thread1.start();
thread2.start();
}
//
static class SynchronizedTest{
public void print(String name){
synchronized (SynchronizedTest.class){
for(int i=0;i<100;i++)
System.out.println(name+"第"+i+"次执行了方法");
}
}
}
俩次结果一样
猜想:虽然new了俩个SynchronizedTest ,但是里面的锁对象确实Class对象,也就是说锁对象使用的是同一个,所以才出现这个结果
不妨大胆假设:如果使用的锁对象是同一个,那么锁对象在被使用的情况下,其他线程就要等待。
//第四次测试,类的this对象,并且也new了俩个SynchronizedTest对象
public static void main(String[] agrs){
SynchronizedTest synchronizedTest1=new SynchronizedTest();
SynchronizedTest synchronizedTest2=new SynchronizedTest();
MyThread thread1=new MyThread("小明",synchronizedTest1);
MyThread thread2=new MyThread("小王",synchronizedTest2);
thread1.start();
thread2.start();
}
//
static class SynchronizedTest{
public void print(String name){
synchronized (this){
for(int i=0;i<100;i++)
System.out.println(name+"第"+i+"次执行了方法");
}
}
}
结果:这次不是小明执行完后,小王才执行,好像符合我们的猜想,
//第五次测试,类的this对象,下面只new了一个SynchronizedTest对象
public static void main(String[] agrs){
SynchronizedTest synchronizedTest1=new SynchronizedTest();
MyThread thread1=new MyThread("小明",synchronizedTest1);
MyThread thread2=new MyThread("小王",synchronizedTest1);
thread1.start();
thread2.start();
}
//
static class SynchronizedTest{
public void print(String name){
synchronized (this){
for(int i=0;i<100;i++)
System.out.println(name+"第"+i+"次执行了方法");
}
}
}
结果:小明执行完了,小王才执行
猜想:因为只new了一个,所以里面的this对象是同一个,所以同步代码块里一次只能进入一个线程
结论
:从这就可以断定了,只要锁对象使用同一个,就可以达到同步的效果
五、synchronized的其他用法
1.使用在普通方法上,此时synchronized的锁对象为当前类的this对象
public synchronized void print(String name){
for(int i=0;i<100;i++)
System.out.println(name+"第"+i+"次执行了方法");
}
2.使用在静态方法上,此时synchronized的锁对象为当前类的Class对象
static class SynchronizedTest{
public static synchronized void print(String name){
for(int i=0;i<100;i++)
System.out.println(name+"第"+i+"次执行了方法");
}
}
~~根据结论可以试着猜下结果