使用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对象却是同一个, 也就是上的其实是同一把锁.