问题:static 修饰的Synchronized 方法和非 static Synchronized 方法区别?
这个问题是一个同事在一次无意间中问过我的;在解释之前,我们先来看两个demo;我觉得通过代码来讲解释最容易理解的:
demo1:
/**
*
* @author leo-zeng
*
*/
public class SynchronizedDemo {
public static synchronized void staticTest() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
System.out.println("static test"+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void test() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
System.out.println(" test"+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
//SynchronizedDemo 类的两个实例
final SynchronizedDemo d1 = new SynchronizedDemo();
final SynchronizedDemo d2 = new SynchronizedDemo();
//线程1
Thread thread1 = new Thread(new Runnable() {
public void run() {
d1.test();
}
}, "a");
//线程2
Thread thread2 = new Thread(new Runnable() {
public void run() {
d2.test();
}
}, "b");
thread1.start();
thread2.start();
}
}
demo1 得到的结果是:
testa
testb
testa
testb
testa
testb
testa
testb
testa
testb
发现Synchronized 对于本例中并没有起作用;
再看看demo2:
/**
*
* @author leo-zeng
*
*/
public class StaticSynchronizedDemo {
public static synchronized void staticTest() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
System.out.println("static test"+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void test() {
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
System.out.println(" test"+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
final StaticSynchronizedDemo d1 = new StaticSynchronizedDemo();
final StaticSynchronizedDemo d2 = new StaticSynchronizedDemo();
Thread thread1 = new Thread(new Runnable() {
public void run() {
StaticSynchronizedDemo.staticTest();
}
}, "b");
Thread thread2 = new Thread(new Runnable() {
public void run() {
StaticSynchronizedDemo.staticTest();
}
}, "a");
thread1.start();
thread2.start();
}
}
得到的结果:
static testb
static testb
static testb
static testb
static testb
static testa
static testa
static testa
static testa
static testa
发现 两个线程被Synchronized 加上说了;线程同步走了; 为什么会这样呢;其实从两个例子就很好的回答了上面那个问题。
synchronized是对类的当前实例进行加锁,防止其他线程同时访问该类的该实例的所有synchronized块,记住看好了是该类的”当前实例“;demo1中 我们线程调用的是类的不同实例,所以synchronized对类的不同实例没有约束。再看看demo2;static synchronized恰好就是要控制类的所有实例的访问了,static synchronized是限制线程同时访问jvm中该类的所有实例同时访问对应的代码快。实际上,在类中某方法或某代码块中有 synchronized,那么在生成一个该类实例后,改类也就有一个监视快,放置线程并发访问改实例synchronized保护块,而static synchronized则是所有该类的实例公用一个监视快了,也也就是两个的区别了;可以总结说:synchronized 是 this.synchronized;而static synchronized 是类的synchronized;
拓展:
看下demo3
public class SynchronizedDemo3 {
private final static Integer lock = new Integer(0);
/**
* 静态方法
*/
public static void staticTest(){
//锁住lock 对象
synchronized (lock) {
for (int i = 0; i < 3; i++) {
try {
Thread.sleep(1000);
System.out.println(" static test"+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public void test(){
synchronized (lock) {
for (int i = 0; i < 3; i++) {
try {
Thread.sleep(1000);
System.out.println(" test"+Thread.currentThread().getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
final SynchronizedDemo3 s1 =new SynchronizedDemo3();
final SynchronizedDemo3 s2 =new SynchronizedDemo3();
Thread thread1 = new Thread(new Runnable() {
public void run() {
SynchronizedDemo3.staticTest();
}
}, "b");
Thread thread2 = new Thread(new Runnable() {
public void run() {
s1.test();
}
}, "a");
Thread thread3 = new Thread(new Runnable() {
public void run() {
s2.test();
}
}, "c");
thread1.start();
thread2.start();
thread3.start();
}
}
得到的结果就是
static testb
static testb
static testb
testc
testc
testc
testa
testa
testa
因为Syssynchronized (lock) ;加在同一个object 对象上;所以就确保了类的所有对象都能约束到了。
y