synchronized


synchronized的使用方式有两种

  1 对一个对象进行加锁

  

synchronized(O){
    //代码
}

  2 对一个方法加锁

public synchornized void func(){
    //代码
}

其实无论是对一个对象进行加锁还是对一个方法进行加锁,实际上,都是对对象进行加锁

java中一个对象由三部分组成=>

1 对象头=>markwork(hashCode(只有在调用后才会有),GC分代年龄,锁信息),class指针,如果是数组的话还会有一个数组的长度

2 实例数据=》存放对象字段的数据

3 填充数据=》为了保证一个对象所占用的字节数是8的倍数,提高执行效率

4 如果对象是数组的话对象头

 偏向锁的概念一直不太好理解,偏向锁其实没有上锁,只是将线程指针加到对象头中,在更改的时候原理是cas。之所要偏向锁,是因为大部分情况下都是一个进程在操作,当有竞争的时候,需要将锁升级(一般升级为轻量级锁,如果加了await就直接进入重量级锁,在升为轻量级锁的时候,偏向的线程也要和其他的线程重新进行cas操作来获取锁),但是在升级的时候会让偏向的这个线程先获取锁,偏向锁的意义就是为了让偏向的线程先获取锁。

偏向锁产生的条件?=》只有偏向锁已启动(即偏向锁的标志位为1)的对象才能产生偏向锁,如果没有则直接进入轻量级锁。

对象如何启动偏向?=》只有在jvm启动一段时间(一般4秒钟)后创建的对象jvm才会给该对象头的偏向锁标志位设置为1。

代码示例:

    public static void main(String[] args)  {

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(() -> {

            Object o = new Object();
            synchronized (o){
                System.out.println(ClassLayout.parseInstance(o).toPrintable());
            }
        }).start();
}

 偏向锁是否一定比自旋锁效率高?

  不一定,在明确知道会有多线程竞争的情况下,偏向锁肯定会涉及锁撤销,这时候直接使用自旋锁。

可见性:

JMM关于synchronized的两条规定:

1)在线程执行的代码中遇到释放锁前,必须把工作内存中共享变量的最新值刷新到主内存中

2)在线程执行的代码中中遇到获得锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中重新获取最新的值

public class Test
{
    private static int x = 0;
    private static int y = 0;

    public static void main(String[] args) {

        new Thread(() -> {
            while (true) {
                synchronized (Test.class) {
                }
                if (x == 1 & y == 2) {
                    System.out.println("thread1 end");
                    break;
                }
            }

        }).start();

        new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            x = 1;
            y = 2;
        }).start();

        System.out.println("main is end");


    }
}
原文地址:https://www.cnblogs.com/Tony100/p/12922458.html