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

2017-11-04  本文已影响18人  是一动不动的friend
    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.锁对象的改变:将任何数据类型作为同步锁时,需要注意的是,是否有多个线程同时持有锁对象,如果同时持有相同的锁对象,则这些线程之间就是同步的,之后即使对象的属性改变了,也还是同步的;如果分别获得锁对象,这些线程之间就是异步的。

上一篇下一篇

猜你喜欢

热点阅读