美文网首页
Synchronized关键字详解2(对非object持锁)

Synchronized关键字详解2(对非object持锁)

作者: 是一动不动的friend | 来源:发表于2017-11-04 11:13 被阅读18次
        1.静态同步Synchronized方法与Synchronized(class)代码块:关键字Synchronized还可以应用在static静态方法上,如果这样写,那是对当前的*.java文件对应的Class类进行持锁。class锁和对象锁的区别就在于class锁可以对所有对象实例起作用。
      但是如果两个方法都被Synchronized修饰一个是静态另一个是动态,那么在这种情况下,只有一个对象实例时,多个线程调用两个方法不是同步的。因为调用两个方法一个持有对象锁另一个持有Class锁。
       Class锁对所有实例对象起作用体现在,当有不同线程持有不同实例对象时,执行Synchronized修饰的静态方法仍然同步。
    
    2.同步Synchronized(class)代码块的作用其实和Synchronized static方法作用一样。
    
    3.在JVM中具有String常量池缓存功能。数据类型String的常量池特性:将Synchronized(string)同步块与String联合使用时,要注意常量池以带来的一些例外。代码如下:
    
    public class Service{
        public static void print(String stringParam){
            try {
            synchronized (stringParam){
                while (true){
                    System.out.println(Thread.currentThread().getName());
                    Thread.sleep(1000);
                }
            }
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
    }
    
    public class ThreadA extends Thread{
        private Service service;
        public ThreadA(Service service){
            super();
            this.service = service;
        }
    
        @Override
        public void run(){
            service.print("AA");
        }
    }
    
    public class ThreadB extends Thread{
        private Service service;
        public ThreadB(Service service){
            super();
            this.service = service;
        }
    
        @Override
        public void run(){
            service.print("AA");
        }
    }
    
    public static void main(String[] args){
        Service service = new Service();
        ThreadA a = new ThreadA(service);
        a.setName("A");
        a.start();
        ThreadB b = new ThreadB(service);
        b.setName("B");
        b.start();
    }
    
       以上代码执行时B线程不能执行,因为String的两个值都是AA。两个线程持有相同的锁,所以造成线程B不能执行。这就是String常量池所带来的问题。因为在大多数情况下,同步synchronized代码块都不使用String作为锁对象,而改用其他,比如new Object实例化一个Object对象,但它并不放入缓存中。
    

    4.死锁:同步方法容易造成死锁。Java线程死锁是一个经典的多线程问题,因为不同的线程都在等待根本不可能被释放的锁,从而导致所有的任务都无法继续完成。在多线程技术中,“死锁”是必须避免的,因为这会造成线程假死。
    死锁是程序设计的Bug,在设计程序时就要避免双方互相持有对方法的锁的情况。需要说明的是不只是使用synchronized才会形成死锁,不使用synchronized也会形成死锁。
    如何检测死锁?进入JDK的安装文件夹中的bin目录,执行jps命令,得到运行的线程Run的id值是3244。再执行jstack命令察看结果是否有死锁现象。

    5.内置类和内置静态类:内置类中被synchronized修饰的同步方法所持有的对象的监视器是该内部类。

    6.锁对象的改变:将任何数据类型作为同步锁时,需要注意的是,是否有多个线程同时持有锁对象,如果同时持有相同的锁对象,则这些线程之间就是同步的,之后即使对象的属性改变了,也还是同步的;如果分别获得锁对象,这些线程之间就是异步的。

    相关文章

      网友评论

          本文标题:Synchronized关键字详解2(对非object持锁)

          本文链接:https://www.haomeiwen.com/subject/tcfxmxtx.html