Java~使用synchronized修饰静态方法带来的问题 与 同步synchronized代码块不使用String作为锁对象的原因

使用synchronized修饰静态方法带来的问题

  • 直接上代码
/**
 * Created with IntelliJ IDEA.
 * Description: If you don't work hard, you will a loser.
 * User: Listen-Y.
 * Date: 2020-09-29
 * Time: 11:39
 */
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;

/**
 * Created with IntelliJ IDEA.
 * Description: If you don't work hard, you will a loser.
 * User: Listen-Y.
 * Date: 2020-09-29
 * Time: 11:41
 */
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) {
    
    
        //给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对象却是同一个, 也就是上的其实是同一把锁.

猜你喜欢

转载自blog.csdn.net/Shangxingya/article/details/108874746
今日推荐