前言:
有人觉得使用静态变量作为对象锁,用的是类锁,还有人觉得静态变量在使用的过程中,里面的值改变,对象的地址会改变,所以用的就不是通一把锁,今天我们验证下。
一、使用同一把静态变量锁的情况:
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的对象锁,虽然是静态变量,但使用的不是类锁。
使用静态变量,对静态变量值的改变,不会影响到此变量的地址,用的依然是同一把锁。