前言:
有人覺得使用靜態變量作爲對象鎖,用的是類鎖,還有人覺得靜態變量在使用的過程中,裏面的值改變,對象的地址會改變,所以用的就不是通一把鎖,今天我們驗證下。
一、使用同一把靜態變量鎖的情況:
public class SynchronizeTest {
public static List<Person>list1;
static {
list1 = new ArrayList<>();
}
public static void method1(){
new Thread(new Runnable() {
@Override
public void run() {
synchronized (list1) {
for (int i = 0; i < 20; i++) {
System.out.println("method1");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}).start();
}
public static void method2(){
new Thread(new Runnable() {
@Override
public void run() {
synchronized (list1) {
for (int i = 0; i < 20; i++) {
System.out.println("method2");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}).start();
}
public static void main(String[] args) {
SynchronizeTest t1 = new SynchronizeTest();
SynchronizeTest t2 = new SynchronizeTest();
t1.method1();
t2.method2();
}
結果:
運行完method1後再運行method2;因此使用的是同一把鎖,但只要使用靜態變量就是類鎖嗎?不是的,結果看實驗二。
二、使用不同的靜態變量鎖的情況:
public class SynchronizeTest {
public static List<Person>list1;
public static List<Person>list2;
static {
list1 = new ArrayList<>();
list2 = new ArrayList<>();
}
public static void method1(){
new Thread(new Runnable() {
@Override
public void run() {
synchronized (list1) {
for (int i = 0; i < 20; i++) {
System.out.println("method1");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}).start();
}
public static void method2(){
new Thread(new Runnable() {
@Override
public void run() {
synchronized (list2) {
for (int i = 0; i < 20; i++) {
System.out.println("method2");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}).start();
}
public static void main(String[] args) {
SynchronizeTest t1 = new SynchronizeTest();
SynchronizeTest t2 = new SynchronizeTest();
t1.method1();
t2.method2();
}
}
結果:method1和method2交替運行。因此,使用靜態變量作爲鎖,用的不是類鎖。
三、對靜態變量值的改變,對鎖是否有影響。
我在對method1和method2這兩個方法使用list1這個鎖的過程中,開闢了第三個線程對list1的值的改變,發現list1這個鎖的不受影響,依然是method1執行完畢後再執行method2。
public class SynchronizeTest {
public static Person person;
public static List<Person>list1;
static {
list1 = new ArrayList<>();
person = new Person(0);
}
public static void method1(){
new Thread(new Runnable() {
@Override
public void run() {
synchronized (list1) {
for (int i = 0; i < 20; i++) {
System.out.println("method1");
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}).start();
}
public static void method2(){
new Thread(new Runnable() {
@Override
public void run() {
synchronized (list1) {
for (int i = 0; i < 20; i++) {
System.out.println("method2");
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}).start();
}
public static void method3(){
new Thread(new Runnable() {
@Override
public void run() {
for(int i=0;i<20;i++){
try {
Thread.sleep(20);
System.out.println("-----");
} catch (InterruptedException e) {
e.printStackTrace();
}
Person p = new Person(i);
list1.add(person);
}
}
}).start();
}
public static void main(String[] args) {
SynchronizeTest t1 = new SynchronizeTest();
SynchronizeTest t2 = new SynchronizeTest();
SynchronizeTest t3 = new SynchronizeTest();
t1.method1();
t2.method2();
t3.method3();
}
}
最後總結:
使用list1和list2後使用的分別是list1和list2的對象鎖,雖然是靜態變量,但使用的不是類鎖。
使用靜態變量,對靜態變量值的改變,不會影響到此變量的地址,用的依然是同一把鎖。