使用synchronized修饰静态方法带来的问题
public class ServiceStatic {
public synchronized static void printA() {
System.out.println(System.currentTimeMillis() + "进入printA_Static");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis() + "离开printA_Static");
}
public synchronized static void printB() {
System.out.println(System.currentTimeMillis() + "进入printB_Static");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis() + "离开printB_Static");
}
public void printC() {
System.out.println(System.currentTimeMillis() + "进入printC");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis() + "离开printC");
}
}
import javax.net.ssl.SSLContext;
public class Run5 {
public static void main(String[] args) {
Thread thread = new Thread("A") {
@Override
public void run() {
while (true) {
ServiceStatic.printA();
}
}
};
Thread thread1 = new Thread("B") {
@Override
public void run() {
while (true) {
ServiceStatic.printB();
}
}
};
ServiceStatic serviceStatic = new ServiceStatic();
Thread thread2 = new Thread("C") {
@Override
public void run() {
while (true) {
serviceStatic.printC();
}
}
};
thread.start();
thread1.start();
thread2.start();
}
}
1601380417431进入printA_Static
1601380417431进入printC
1601380417531离开printA_Static
1601380417531离开printC
1601380417531进入printC
1601380417531进入printA_Static
1601380417631离开printC
1601380417631进入printC
1601380417632离开printA_Static
1601380417632进入printA_Static
1601380417732离开printC
1601380417732进入printC
1601380417733离开printA_Static
1601380417733进入printB_Static
1601380417832离开printC
1601380417832进入printC
1601380417833离开printB_Static
1601380417833进入printB_Static
1601380417932离开printC
1601380417932进入printC
- 观察我们发现虽然我们给三个方法printA printB printC 都上了锁, 但是运行结果却是printA与printB是同步的, 与printC是异步的
- 这就是给static方法上锁带来的问题, 其实异步的原因是持有不同的锁, 一个是实例对象锁, 一个是类对象锁, 而且类对象锁可以对所有对象实例起到作用, 而printC是只对调用这个方法的那个实例对象其作用
同步synchronized代码块不使用String作为锁对象的原因
public class Service {
public void printStr(String str) {
synchronized (str) {
while (true) {
System.out.println(Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class ThreadA extends Thread {
private Service service;
public ThreadA(Service service) {
this.service = service;
}
@Override
public void run() {
service.printStr("Listen");
}
}
class ThreadB extends Thread {
private Service service;
public ThreadB(Service service) {
this.service = service;
}
@Override
public void run() {
service.printStr("Listen");
}
}
public class Run4 {
public static void main(String[] args) {
Service service = new Service();
ThreadA threadA = new ThreadA(service);
threadA.setName("A");
ThreadB threadB = new ThreadB(service);
threadB.setName("B");
threadA.start();
threadB.start();
}
}
A
A
A
A
A
A
Process finished with exit code -1
- 分析结果我们发现, A和B俩个线程都启动了, 但是B线程一直没有得到执行, 也就是B线程一直没有获得锁
- 这就是使用String作为锁对象带来的问题, 原因就是JVM中有String常量池缓存的功能, 看下面代码示例
public class Test {
public static void main(String[] args) {
String s = "Listen";
String s1 = "Listen";
System.out.println(s==s1);
}
}
true
- 由此我们得出, 虽然线程A和线程B传入的不是同一个引用的字符串, 但是这个String对象却是同一个, 也就是上的其实是同一把锁.