批量重偏向与批量释放

2022-07-26,,

查看http://hg.openjdk.java.net/jdk8u/jdk8u60/hotspot/file/37240c1019fd/src/share/vm/oops/markOop.hpp

biased object注释看得出偏向锁存储的为线程信息。

配置参数查看jvm初始批量重偏向与批量撤销的阈值:

误区:有时候你发现没有超过阈值发生重偏向:

引入:

  <!-- https://mvnrepository.com/artifact/org.openjdk.jol/jol-core -->
        <dependency>
            <groupId>org.openjdk.jol</groupId>
            <artifactId>jol-core</artifactId>
            <version>0.9</version>
        </dependency>
package sync;

import org.openjdk.jol.info.ClassLayout;

import java.util.ArrayList;
import java.util.List;

public class SyncExplore2 {
    static Thread t1;
    static Thread t2;
    public static void main(String[] args) {
        try {
            Thread.sleep(5000);
            final List<DouFuDan> list = new ArrayList<DouFuDan>();
            t1 = new Thread() {
                @Override
                public void run() {
                    for (int i = 0; i < 100; i++) {
                        DouFuDan douFuDan = new DouFuDan();
                        synchronized (douFuDan) {
                            if (i == 1) {
                                System.out.println("t1 locking");
                                System.out.println(ClassLayout.parseInstance(douFuDan).toPrintable());
                            }
                            list.add(douFuDan);
                        }
                    }
                }
            };
            t1.start();
            Thread.sleep(3000);
            t2 = new Thread() {
                @Override
                public void run() {
                    for (int i = 0; i < 20; i++) {
                        DouFuDan douFuDan = list.get(i);
                        synchronized (douFuDan) {
                            if (i == 2 || i == 3 || i == 4) {
                                System.out.println("t2 locking");
                                System.out.println(ClassLayout.parseInstance(douFuDan).toPrintable());
                            }
                        }
                    }
                }
            };
            t2.start();
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}

你会发现:

没到达到阈值没有变为轻量级锁,但是仔细一看存储的线程id一样的,哦,原来并没有重偏向线程2,怀疑:jvm可能让t2复用了t1的线程id,导致认为线程1没有挂掉,还保持偏向。

批量重偏向:

package sync;

import org.openjdk.jol.info.ClassLayout;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.LockSupport;

/**
 * 批量重偏向
 */
public class SyncExplore1 {
    static Thread t1;
    static Thread t2;
    public static void main(String[] args) {
        try {
            Thread.sleep(5000);
            final List<DouFuDan> list = new ArrayList<DouFuDan>();
            t1 = new Thread() {
                @Override
                public void run() {
                    for (int i = 0; i < 100; i++) {
                        DouFuDan douFuDan = new DouFuDan();
                        synchronized (douFuDan) {
                            if (i == 2) {
                                System.out.println("t1 locking");
                                System.out.println(ClassLayout.parseInstance(douFuDan).toPrintable());
                            }
                            list.add(douFuDan);
                        }
                    }
                    LockSupport.unpark(t2);
                }
            };
            t1.start();
            t2 = new Thread() {
                @Override
                public void run() {
                    LockSupport.park();
                    for (int i = 0; i < 20; i++) {
                        DouFuDan douFuDan = list.get(i);
                        synchronized (douFuDan) {
                            if (i == 19) {
                                System.out.println("t2 locking");
                                System.out.println(ClassLayout.parseInstance(douFuDan).toPrintable());
                            }
                        }
                    }
                }
            };
            t2.start();
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}

两个偏向锁的线程信息不一样,当对一个对象进行偏量锁撤销为无锁再变成轻量锁时epoch计数进行加一,当加到阈值20时,epoch的2个bit标识变为10,这时候jvm认为Class偏向锁出现了问题,会重新添加偏向锁。

批量撤销:

package sync;

import org.openjdk.jol.info.ClassLayout;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.LockSupport;

/**
 * 批量撤销
 */
public class SyncExplore {
    static Thread t1;
    static Thread t2;
    static Thread t3;
    public static void main(String[] args) {
        try {
            Thread.sleep(5000);
            final List<DouFuDan> list = new ArrayList<DouFuDan>();
            t1 = new Thread() {
                @Override
                public void run() {
                    for (int i=0;i<100;i++) {
                        DouFuDan douFuDan = new DouFuDan();
                        synchronized (douFuDan) {
                            if(i==0) {
                                System.out.println("t1 locking");
                                System.out.println(ClassLayout.parseInstance(douFuDan).toPrintable());
                            }
                            list.add(douFuDan);
                        }
                    }
                    LockSupport.unpark(t2);
                }
            };
            t1.start();
            t2 = new Thread() {
                @Override
                public void run() {
                    LockSupport.park();
                    for (int i=0;i<list.size();i++) {
                        DouFuDan douFuDan = list.get(i);
                        synchronized (douFuDan) {
                            if(i == 19) {
                                System.out.println("t2 locking");
                                System.out.println(ClassLayout.parseInstance(douFuDan).toPrintable());
                            }
                        }
                    }
                    LockSupport.unpark(t3);
                }
            };
            t2.start();
            t3 = new Thread() {
                @Override
                public void run() {
                    LockSupport.park();
                    for (int i=20;i<list.size();i++) {
                        DouFuDan douFuDan = list.get(i);
                        synchronized (douFuDan) {
                            if(i == 40) {
                                System.out.println("t3 locking");
                                System.out.println(ClassLayout.parseInstance(douFuDan).toPrintable());
                            }
                        }
                    }
                }
            };
            t3.start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

发现到达40阈值的时候,锁变为了轻量级锁,epoch计数加到40,epoch标志位变为01,可能是jvm认为存在线程竞争,标记为不可偏向,直接升级为轻量级锁。

本文地址:https://blog.csdn.net/qq_33554285/article/details/110818070

《批量重偏向与批量释放.doc》

下载本文的Word格式文档,以方便收藏与打印。