1.synchronized的场景
synchronized是在并发下对方法可以实现加锁的效果,保证只有一个线程能够进入方法,那么一个类下有两个静态方法都用synchronized修饰的情况下,两个线程分别调用不同的方法是否会阻塞呢?
有三种场景:
1. 调用的方法都为同步的普通方法
2. 调用的方法有一个是静态同步,一个为普通同步方法
3. 调用的方法都为静态同步方法
下面我会依不同的场景用代码来展示运行的效果
1.1调用的方法都为同步的普通方法
package com.xncoding.pos.test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TheadTest {
public synchronized void say1() {
try {
//synchronized(o) {
System.out.println("say1111111111");
Thread.sleep(10000);
//}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public synchronized void say2() {
try {
// synchronized(o1) {
System.out.println("say222222222222222222");
Thread.sleep(2000);
// }
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
TheadTest t=new TheadTest();
ExecutorService es=Executors.newFixedThreadPool(2);
es.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
t.say1();
}
});
es.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
t.say2();
}
});
}
}
执行结果:
say1111111111
say222222222222222222
因为是线程休眠,控制台最终打印的结果是没什么区别的,执行过程中两个线程不是同步执行的,先打印say1方法,10s后才执行say2方法,说明两个方法的锁是同一个,就是创建出来的实例,线程1获取到锁执行say1方法时,此时线程2去获取对象锁,发现已经被占用,只能等线程1执行完释放对象锁,线程2才能运行
1.2 调用的方法有一个是静态同步,一个为普通同步方法
package com.xncoding.pos.test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TheadTest {
public synchronized static void say1() {
try {
//synchronized(o) {
System.out.println("say1111111111");
Thread.sleep(10000);
//}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public synchronized void say2() {
try {
// synchronized(o1) {
System.out.println("say222222222222222222");
Thread.sleep(2000);
// }
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
TheadTest t=new TheadTest();
ExecutorService es=Executors.newFixedThreadPool(2);
es.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
TheadTest.say1();
}
});
es.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
t.say2();
}
});
}
}
执行结果
say1111111111
say222222222222222222
打印内容同时输出,说明两个线程是同步执行类中各自的方法,静态方法和普通方法是持有不同的锁,互相不影响,线程1获取的是class锁,线程2获取的是实例的对象锁
1.3 调用的方法都为静态同步方法
package com.xncoding.pos.test;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TheadTest {
public synchronized static void say1() {
try {
//synchronized(o) {
System.out.println(Thread.currentThread().getName()+" say1111111111");
Thread.sleep(10000);
//}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public synchronized static void say2() {
try {
// synchronized(o1) {
System.out.println(Thread.currentThread().getName()+" say222222222222222222");
Thread.sleep(2000);
// }
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
TheadTest t=new TheadTest();
ExecutorService es=Executors.newFixedThreadPool(2);
es.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
TheadTest.say1();
}
});
es.execute(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
TheadTest.say2();
}
});
}
}
执行结果:
pool-1-thread-1 say1111111111
pool-1-thread-2 say222222222222222222
say2方法是在say1方法10s后才打印,说明两个线程有阻塞,争夺都是class锁
2 总结
静态方法的锁是class对象,调用时会为了争夺而发生阻塞,普通方法的锁是实例对象,只要实例对象不同,不会发生阻塞