synchronized锁住了什么?
一、放在静态方法与普通方法
public class SynchronizedTest implements Runnable {
static int count = 0;
int type;
public SynchronizedTest(int type) {
this.type = type;
}
static synchronized void staticAdd1() {
while (count < 10) {
count++;
System.out.println(Thread.currentThread().getName() + ":" + count);
}
}
static synchronized void staticAdd2() {
while (count < 10) {
count++;
System.out.println(Thread.currentThread().getName() + ":" + count);
}
}
@Override
public void run() {
if (type == 0) {
staticAdd1();
} else if(type==1) {
staticAdd2();
}else if(type==2) {
commonadd1();
}else {
commonadd2();
}
}
public synchronized void commonadd1() {
while (count < 10) {
count++;
System.out.println(Thread.currentThread().getName() + ":" + count);
}
}
public synchronized void commonadd2() {
while (count < 10) {
count++;
System.out.println(Thread.currentThread().getName() + ":" + count);
}
}
}
SynchronizedTest synchronizedTest1 = new SynchronizedTest(staticAdd1); SynchronizedTest synchronizedTest2 = new SynchronizedTest(staticAdd1); //不同实例相同静态方法 new Thread(synchronizedTest1).start(); new Thread(synchronizedTest2).start(); |
SynchronizedTest synchronizedTest1 = new SynchronizedTest(staticAdd1); SynchronizedTest synchronizedTest2 = new SynchronizedTest(staticAdd2); //不同实例不同静态方法 new Thread(synchronizedTest1).start(); new Thread(synchronizedTest2).start(); | SynchronizedTest synchronizedTest1 = new SynchronizedTest(commonadd1); SynchronizedTest synchronizedTest2 = new SynchronizedTest(commonadd1); //不同实例相同普通方法 new Thread(synchronizedTest1).start(); new Thread(synchronizedTest2).start(); | SynchronizedTest synchronizedTest1 = newSynchronizedTest(commonadd1); SynchronizedTest synchronizedTest2 = newSynchronizedTest(commonadd2); //不同实例在不同普通方法 new Thread(synchronizedTest1).start(); new Thread(synchronizedTest2).start(); |
Thread-0:1 Thread-0:2 Thread-0:3 Thread-0:4 Thread-0:5 Thread-0:6 Thread-0:7 Thread-0:8 Thread-0:9 Thread-0:10 | Thread-0:1 Thread-0:2 Thread-0:3 Thread-0:4 Thread-0:5 Thread-0:6 Thread-0:7 Thread-0:8 Thread-0:9 Thread-0:10 |
Thread-0:2
Thread-1:2
Thread-0:3
Thread-0:5
Thread-1:4
Thread-1:7
Thread-0:6
Thread-1:8
Thread-0:9
Thread-1:10
Thread-0:2
Thread-0:3
Thread-0:4
Thread-1:2
Thread-1:6
Thread-1:7
Thread-0:5
Thread-1:8
Thread-0:9
Thread-1:10
通过上面的测试:
在静态代码块加锁,会锁住对象,两个线程操作的是不同的实例,不管方法是否相同,但是只有第一个线程完全执行完后,第二个线程才会进入同步方法,但是第一个线程已经加到10了,所以第二个线程不满足循环条件直接返回。
在普通方法加锁,锁住的是实例,两个线程操作的是不同的实例,两个线程可以进入各自实例的同步代码方法,count是一个全局静态共享变量放在方法区,所以两个线程可以同时修改。
二、放在代码块与放在普通方法
1.同一个实例的不同同步方法与不同同步代码块的对比
public class SynchronizedTest {
public void method1() {
System.out.println("Method 1 start");
try {
synchronized (this) {
System.out.println("Method 1 execute");
Thread.sleep(3000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 1 end");
}
public void method2() {
System.out.println("Method 2 start");
try {
synchronized (this) {
System.out.println("Method 2 execute");
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 2 end");
}
public synchronized void method3() {
System.out.println("Method 3 start");
try {
System.out.println("Method 3 execute");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 3 end");
}
public synchronized void method4() {
System.out.println("Method 4 start");
try {
System.out.println("Method 4 execute");
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Method 4 end");
}
}
final SynchronizedTest test = new SynchronizedTest(); new Thread(new Runnable() { @Override public void run() { test.method1(); } }).start();
new Thread(new Runnable() { @Override public void run() { test.method2(); } }).start(); | final SynchronizedTest test = new SynchronizedTest(); new Thread(new Runnable() { @Override public void run() { test.method3(); } }).start();
new Thread(new Runnable() { @Override public void run() { test.method4(); } }).start(); |
Method 1 start Method 1 execute Method 2 start Method 1 end Method 2 execute Method 2 end | Method 3 start Method 3 execute Method 3 end Method 4 start Method 4 execute Method 4 end |
加在方法上的锁,只有上一个获得实例锁的方法执行完成后,另一个方法才能执行,如果加在代码块,方法是可以同时进入,只会在执行同步代码块的时候会去竞争锁
2.多线程操作同一个实例的同一个方法
final SynchronizedTest test = new SynchronizedTest();
new Thread(new Runnable() { @Override public void run() { test.method1(); } }).start();
new Thread(new Runnable() { @Override public void run() { test.method1(); } }).start(); |
new Thread(new Runnable() { @Override public void run() { test.method3(); } }).start();
new Thread(new Runnable() { @Override public void run() { test.method3(); } }).start(); |
Thread-0Method 1 start Thread-0Method 1 execute Thread-1Method 1 start Thread-1Method 1 execute Thread-0Method 1 end Thread-1Method 1 end | Thread-0Method 3 start Thread-0Method 3 execute Thread-0Method 3 end Thread-1Method 3 start Thread-1Method 3 execute Thread-1Method 3 end |
可以看出加锁的范围在代码块比在方法上小