Java9 新特性之核心库

Posted by NotGeek on May 28, 2020

Java 9 新特性之核心库(上)

TOC

[TOC]

主要议题

  • Java 9 新特性简介
  • Java 9 核心库
  • 问答互动

新特性简介

重要新特性

  • 模块化
  • 核心库
  • 安全
  • 部署
  • JVM
  • 调优

详情

  • http://docs.oracle.com/javase/9/whatsnew/toc.htm

Java 9 的模块化,最大的更新

  • jshell 的东西

在 Java 6 的时候,有 javascript on JVM

还有 Java 8 jcmd 可以调节参数

同一个类可以在不同的 jar 包用不同的 版本。

PropertyPermission

在设置 #setProperties 的时候,就需要权限。

  • jdeps 分析数

Java doc 需要很好写

javac 就是 java compile

  • Source
  • Compile

invokedynamic

  • 动态生成字节码指令

JVM.logger

  • 统一的 Java 日志,要知道生产的状态,

GI 默认的垃圾回收

CMS 淘汰掉了

G1 - 越来越偏向与 服务器,提升吞吐量

CMS 托管了,让大家取维护。

讨论范围

  • 集合工厂方法(Factory Method of Collections)
  • 进程(Process)
  • 统一日志 API(Platform Logging API)
  • 堆栈 API (Stack-Walking API)
  • 变量处理(Variable Handles)
  • 自旋等待提示(Spin-Wait Hints)
  • 压缩字符串(Compact String)

GitHub 资源: https://github.com/mercyblitz

集合工厂方法(Factory Method of Collections)

Guava

  • Lists.newArrayList()

Apache common lang

  • StringUtils

Java

  • Objects

进程(Process)

ProcessHandleDemo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class ProcessHandleDemo {
    public static void main(String[] args) {
        echoOnExit();
        echoAllProcessors();
    }

    private static void echeCurrentProcessonExit() {
        Runtime.getRuntime()
                .addShutdownHook(new Thread(() -> {
                    RuntimeMXBean runtimeMXBean = ManagementFactory.getRuntimeMXBean();
                    String value = runtimeMXBean.getName(); // value=pid@xxx

                    String pid = value.substring(0, value.indexOf("@"));

                    
                    System.out.println("Current [" + ProcessHandle.current().pid()
                            + "]Process while on Exit! ");
                }));
    }

    private static void echoOnExit() {
        ProcessHandle.current()
                .onExit()
                .thenAccept(System.out::println);
    }

    private static void echoAllProcessors() {
        ProcessHandle.allProcesses().forEach(System.out::println);
    }
}

ProcessHandle

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public interface ProcessHandle extends Comparable<ProcessHandle> {

    long pid();

    public static Optional<ProcessHandle> of(long pid) {
        return ProcessHandleImpl.get(pid);
    }

    // 所有的子、孙进程
    Stream<ProcessHandle> descendants();

    // 子进程
    static Stream<ProcessHandle> children(long pid) {
        //。。。
    }


    //    。。。。
}
  • https://github.com/mercyblitz/confucius-commons
1
https://github.com/mercyblitz/confucius-commons
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package org.confucius.commons.lang.process;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.TimeoutException;

/**
 * {@link Process} Executor
 *
 * @author <a href="mailto:[email protected]">Mercy<a/>
 * @version 1.0.0
 * @see ProcessExecutor
 * @since 1.0.0
 */
public class ProcessExecutor {

    private static final long waitForTimeInSecond = Long.getLong("process.executor.wait.for", 1);
    private final String command;
    private final String arguments;
    private final Runtime runtime = Runtime.getRuntime();
    private final ProcessManager processManager = ProcessManager.INSTANCE;
    private boolean finished;

    /**
     * Constructor
     *
     * @param processName
     *         command
     * @param arguments
     *         process arguments
     */
    public ProcessExecutor(String processName, String... arguments) {
        StringBuilder argumentsBuilder = new StringBuilder();
        if (arguments != null) {
            for (String argument : arguments) {
                argumentsBuilder.append(" ").append(argument);
            }
        }
        this.arguments = argumentsBuilder.toString();
        this.command = processName + this.arguments;
    }

    /**
     * Execute current process.
     * <p/>
     * //     * @param inputStream  input stream keeps output stream from process
     *
     * @param outputStream
     *         output stream for process normal or error input stream.
     * @throws IOException
     *         if process execution is failed.
     */
    public void execute(OutputStream outputStream) throws IOException {
        try {
            this.execute(outputStream, Long.MAX_VALUE);
        } catch (TimeoutException e) {
        }
    }

    /**
     * Execute current process.
     * <p/>
     * //     * @param inputStream  input stream keeps output stream from process
     *
     * @param outputStream
     *         output stream for process normal or error input stream.
     * @param timeoutInMilliseconds
     *         milliseconds timeout
     * @throws IOException
     *         if process execution is failed.
     * @throws TimeoutException
     *         if the execution is timeout over specified <code>timeoutInMilliseconds</code>
     */
    public void execute(OutputStream outputStream, long timeoutInMilliseconds) throws IOException, TimeoutException {
        Process process = runtime.exec(command);
        long startTime = System.currentTimeMillis();
        long endTime = -1L;
        InputStream processInputStream = process.getInputStream();
        InputStream processErrorInputStream = process.getErrorStream();
//        OutputStream processOutputStream = process.getOutputStream();
        int exitValue = -1;
        while (!finished) {
            long costTime = endTime - startTime;
            if (costTime > timeoutInMilliseconds) {
                finished = true;
                process.destroy();
                String message = String.format("Execution is timeout[%d ms]!", timeoutInMilliseconds);
                throw new TimeoutException(message);
            }
            try {
                processManager.addUnfinishedProcess(process, arguments);
                while (processInputStream.available() > 0) {
                    outputStream.write(processInputStream.read());
                }
                while (processErrorInputStream.available() > 0) {
                    outputStream.write(processErrorInputStream.read());
                }
                exitValue = process.exitValue();
                if (exitValue != 0) {
                    throw new IOException();
                }
                finished = true;
            } catch (IllegalThreadStateException e) {
                // Process is not finished yet;
                // Sleep a little to save on CPU cycles
                waitFor(waitForTimeInSecond);
                endTime = System.currentTimeMillis();
            } finally {
                processManager.removeUnfinishedProcess(process, arguments);
            }
        }
    }

    /**
     * Wait for specified seconds
     *
     * @param seconds
     *         specified seconds
     */
    private void waitFor(long seconds) {
        try {
            Thread.sleep(seconds * 1000);
        } catch (InterruptedException e) {
            Thread.interrupted();
        }
    }

    /**
     * Check current process finish or not.
     *
     * @return <code>true</code> if current process finished
     */
    public boolean isFinished() {
        return finished;
    }
}

堆栈 API (Stack-Walking API)

  • java.lang.StackWalker
    • java.lang.StackWalker.StackFrame

XXFrame 在 Java 里边是 的意思。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
package org.confucius.commons.lang.reflect;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.ClassUtils;
import org.apache.commons.lang3.reflect.ConstructorUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.commons.lang3.reflect.MethodUtils;

import javax.annotation.Nonnull;
import java.lang.reflect.*;
import java.util.List;
import java.util.Map;

/**
 * Reflection Utility class , generic methods are defined from {@link FieldUtils} , {@link MethodUtils} , {@link
 * ConstructorUtils}
 *
 * @author <a href="mailto:[email protected]">Mercy</a>
 * @version 1.0.0
 * @see Method
 * @see Field
 * @see Constructor
 * @see Array
 * @see MethodUtils
 * @see FieldUtils
 * @see ConstructorUtils
 * @since 1.0.0
 */
public abstract class ReflectionUtils {

    /**
     * Sun JDK 实现类:sun.reflect.Reflection全名称
     */
    public static final String SUN_REFLECT_REFLECTION_CLASS_NAME = "sun.reflect.Reflection";

    /**
     * Current Type
     */
    private static final Class<?> TYPE = ReflectionUtils.class;
    /**
     * sun.reflect.Reflection方法名称
     */
    private static final String getCallerClassMethodName = "getCallerClass";
    /**
     * sun.reflect.Reflection invocation frame
     */
    private static final int sunReflectReflectionInvocationFrame;
    /**
     * {@link StackTraceElement} invocation frame
     */
    private static final int stackTraceElementInvocationFrame;
    /**
     * Is Supported sun.reflect.Reflection ?
     */
    private static final boolean supportedSunReflectReflection;
    /**
     * sun.reflect.Reflection#getCallerClass(int) method
     */
    private static final Method getCallerClassMethod;

    // Initialize sun.reflect.Reflection
    static {
        Method method = null;
        boolean supported = false;
        int invocationFrame = 0;
        try {
            // Use sun.reflect.Reflection to calculate frame
            Class<?> type = Class.forName(SUN_REFLECT_REFLECTION_CLASS_NAME);
            method = type.getMethod(getCallerClassMethodName, int.class);
            method.setAccessible(true);
            // Adapt SUN JDK ,The value of invocation frame in JDK 6/7/8 may be different
            for (int i = 0; i < 9; i++) {
                Class<?> callerClass = (Class<?>) method.invoke(null, i);
                if (TYPE.equals(callerClass)) {
                    invocationFrame = i;
                    break;
                }
            }
            supported = true;
        } catch (Exception e) {
            method = null;
            supported = false;
        }
        // set method info
        getCallerClassMethod = method;
        supportedSunReflectReflection = supported;
        // getCallerClass() -> getCallerClass(int)
        // Plugs 1 , because Invocation getCallerClass() method was considered as increment invocation frame
        // Plugs 1 , because Invocation getCallerClass(int) method was considered as increment invocation frame
        sunReflectReflectionInvocationFrame = invocationFrame + 2;
    }

    // Initialize StackTraceElement
    static {
        int invocationFrame = 0;
        // Use java.lang.StackTraceElement to calculate frame
        StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
        for (StackTraceElement stackTraceElement : stackTraceElements) {
            String className = stackTraceElement.getClassName();
            if (TYPE.getName().equals(className)) {
                break;
            }
            invocationFrame++;
        }
        // getCallerClass() -> getCallerClass(int)
        // Plugs 1 , because Invocation getCallerClass() method was considered as increment invocation frame
        // Plugs 1 , because Invocation getCallerClass(int) method was considered as increment invocation frame
        stackTraceElementInvocationFrame = invocationFrame + 2;
    }

    /**
     * Get Caller class
     *
     * @return 获取调用该方法的Class name
     * @version 1.0.0
     * @since 1.0.0
     */
    @Nonnull
    public static String getCallerClassName() {
        return getCallerClassName(sunReflectReflectionInvocationFrame);
    }

    /**
     * Get Caller Class name
     *
     * @param invocationFrame
     *         invocation frame
     * @return Class name under specified invocation frame
     * @throws IndexOutOfBoundsException
     *         当<code>invocationFrame</code>数值为负数或者超出实际的层次
     * @version 1.0.0
     * @see Thread#getStackTrace()
     * @since 1.0.0
     */
    @Nonnull
    protected static String getCallerClassName(int invocationFrame) throws IndexOutOfBoundsException {
        if (supportedSunReflectReflection) {
            Class<?> callerClass = getCallerClassInSunJVM(invocationFrame + 1);
            if (callerClass != null)
                return callerClass.getName();
        }
        return getCallerClassNameInGeneralJVM(invocationFrame + 1);
    }

    /**
     * 通用实现方式,获取调用类名
     *
     * @return 调用类名
     * @version 1.0.0
     * @see #getCallerClassNameInGeneralJVM(int)
     * @since 1.0.0 2012-3-15 下午03:09:28
     */
    static String getCallerClassNameInGeneralJVM() {
        return getCallerClassNameInGeneralJVM(stackTraceElementInvocationFrame);
    }

    /**
     * 通用实现方式,通过指定调用层次数值,获取调用类名
     *
     * @param invocationFrame
     *         invocation frame
     * @return specified invocation frame 类
     * @throws IndexOutOfBoundsException
     *         当<code>invocationFrame</code>数值为负数或者超出实际的层次
     * @version 1.0.0
     * @see
     * @since 1.0.0 2012-3-15 下午02:43:47
     */
    static String getCallerClassNameInGeneralJVM(int invocationFrame) throws IndexOutOfBoundsException {
        StackTraceElement[] elements = Thread.currentThread().getStackTrace();
        StackTraceElement targetStackTraceElement = elements[invocationFrame];
        return targetStackTraceElement.getClassName();
    }

    static Class<?> getCallerClassInSunJVM(int realFramesToSkip) throws UnsupportedOperationException {
        if (!supportedSunReflectReflection) {
            throw new UnsupportedOperationException("需要SUN的JVM!");
        }
        Class<?> callerClass = null;
        if (getCallerClassMethod != null) {
            try {
                callerClass = (Class<?>) getCallerClassMethod.invoke(null, realFramesToSkip);
            } catch (Exception ignored) {
            }
        }
        if (callerClass != null) {
        }
        return callerClass;
    }

    /**
     * Get caller class in General JVM
     *
     * @param invocationFrame
     *         invocation frame
     * @return caller class
     * @version 1.0.0
     * @see #getCallerClassNameInGeneralJVM(int)
     * @since 1.0.0
     */
    static Class<?> getCallerClassInGeneralJVM(int invocationFrame) {
        String className = getCallerClassNameInGeneralJVM(invocationFrame + 1);
        Class<?> targetClass = null;
        try {
            targetClass = Class.forName(className);
        } catch (ClassNotFoundException impossibleException) {
            throw new IllegalStateException("How can?");
        }
        return targetClass;
    }

    /**
     * Get caller class
     * <p/>
     * For instance,
     * <pre>
     *     package com.acme;
     *     import ...;
     *     class Foo {
     *         public void bar(){
     *
     *         }
     *     }
     * </pre>
     *
     * @return Get caller class
     * @throws IllegalStateException
     *         无法找到调用类时
     * @version 1.0.0
     * @since 1.0.0 2012-2-28 下午07:42:26
     */
    @Nonnull
    public static Class<?> getCallerClass() throws IllegalStateException {
        return getCallerClass(sunReflectReflectionInvocationFrame);
    }

    /**
     * Get caller class In SUN HotSpot JVM
     *
     * @return Caller Class
     * @throws UnsupportedOperationException
     *         If JRE is not a SUN HotSpot JVM
     * @version 1.0.0
     * @see #getCallerClassInSunJVM(int)
     * @since 1.0.0
     */
    static Class<?> getCallerClassInSunJVM() throws UnsupportedOperationException {
        return getCallerClassInSunJVM(sunReflectReflectionInvocationFrame);
    }

    /**
     * Get caller class name In SUN HotSpot JVM
     *
     * @return Caller Class
     * @throws UnsupportedOperationException
     *         If JRE is not a SUN HotSpot JVM
     * @version 1.0.0
     * @see #getCallerClassInSunJVM(int)
     * @since 1.0.0
     */
    static String getCallerClassNameInSunJVM() throws UnsupportedOperationException {
        Class<?> callerClass = getCallerClassInSunJVM(sunReflectReflectionInvocationFrame);
        return callerClass.getName();
    }

    /**
     * @param invocationFrame
     *         invocation frame
     * @return
     * @version 1.0.0
     * @see
     * @since 1.0.0
     */
    static Class<?> getCallerClass(int invocationFrame) {
        if (supportedSunReflectReflection) {
            Class<?> callerClass = getCallerClassInSunJVM(invocationFrame + 1);
            if (callerClass != null)
                return callerClass;
        }
        return getCallerClassInGeneralJVM(invocationFrame + 1);
    }

    /**
     * Get caller class in General JVM
     *
     * @return Caller Class
     * @version 1.0.0
     * @see #getCallerClassInGeneralJVM(int)
     * @since 1.0.0 2012-3-15 下午03:11:16
     */
    static Class<?> getCallerClassInGeneralJVM() {
        return getCallerClassInGeneralJVM(stackTraceElementInvocationFrame);
    }

    /**
     * Get caller class's {@link Package}
     *
     * @return caller class's {@link Package}
     * @throws IllegalStateException
     *         see {@link #getCallerClass()}
     * @version 1.0.0
     * @see #getCallerClass()
     * @since 1.0.0
     */
    public static Package getCallerPackage() throws IllegalStateException {
        return getCallerClass().getPackage();
    }

    /**
     * Assert array index
     *
     * @param array
     *         Array object
     * @param index
     *         index
     * @throws IllegalArgumentException
     *         see {@link ReflectionUtils#assertArrayType(Object)}
     * @throws ArrayIndexOutOfBoundsException
     *         If <code>index</code> is less than 0 or equals or greater than length of array
     */
    public static void assertArrayIndex(Object array, int index) throws IllegalArgumentException {
        if (index < 0) {
            String message = String.format("The index argument must be positive , actual is %s", index);
            throw new ArrayIndexOutOfBoundsException(message);
        }
        ReflectionUtils.assertArrayType(array);
        int length = Array.getLength(array);
        if (index > length - 1) {
            String message = String.format("The index must be less than %s , actual is %s", length, index);
            throw new ArrayIndexOutOfBoundsException(message);
        }
    }

    /**
     * Assert the object is array or not
     *
     * @param array
     *         asserted object
     * @throws IllegalArgumentException
     *         if the object is not a array
     */
    public static void assertArrayType(Object array) throws IllegalArgumentException {
        Class<?> type = array.getClass();
        if (!type.isArray()) {
            String message = String.format("The argument is not an array object, its type is %s", type.getName());
            throw new IllegalArgumentException(message);
        }
    }

    /**
     * Assert Field type match
     *
     * @param object
     *         Object
     * @param fieldName
     *         field name
     * @param expectedType
     *         expected type
     * @throws IllegalArgumentException
     *         if type is not matched
     */
    public static void assertFieldMatchType(Object object, String fieldName, Class<?> expectedType) throws IllegalArgumentException {
        Class<?> type = object.getClass();
        Field field = FieldUtils.getDeclaredField(type, fieldName, true);
        Class<?> fieldType = field.getType();
        if (!expectedType.isAssignableFrom(fieldType)) {
            String message = String.format("The type[%s] of field[%s] in Class[%s] can't match expected type[%s]", fieldType.getName(), fieldName, type.getName(), expectedType.getName());
            throw new IllegalArgumentException(message);
        }
    }


    /**
     * Convert {@link Array} object to {@link List}
     *
     * @param array
     *         array object
     * @return {@link List}
     * @throws IllegalArgumentException
     *         if the object argument is not an array
     */
    @Nonnull
    public static <T> List<T> toList(Object array) throws IllegalArgumentException {
        int length = Array.getLength(array);
        List<T> list = Lists.newArrayListWithCapacity(length);
        for (int i = 0; i < length; i++) {
            Object element = Array.get(array, i);
            list.add((T) toObject(element));
        }
        return list;
    }

    private static Object toObject(Object object) {
        if (object == null) {
            return object;
        }
        Class<?> type = object.getClass();
        if (type.isArray()) {
            return toList(object);
        } else {
            return object;
        }
    }


    /**
     * Read fields value as {@link Map}
     *
     * @param object
     *         object to be read
     * @return fields value as {@link Map}
     */
    @Nonnull
    public static Map<String, Object> readFieldsAsMap(Object object) {
        Map<String, Object> fieldsAsMap = Maps.newLinkedHashMap();
        Class<?> type = object.getClass();
        Field[] fields = type.getDeclaredFields();
        for (Field field : fields) {

            if (Modifier.isStatic(field.getModifiers())) { // To filter static fields
                continue;
            }

            field.setAccessible(true);

            try {
                String fieldName = field.getName();
                Object fieldValue = field.get(object);
                if (fieldValue != null) {
                    Class<?> fieldValueType = fieldValue.getClass();
                    if (ClassUtils.isPrimitiveOrWrapper(fieldValueType)) {
                    } else if (fieldValueType.isArray()) {
                        fieldValue = toList(fieldValue);
                    } else if ("java.lang".equals(fieldValueType.getPackage().getName())) {

                    } else {
                        fieldValue = readFieldsAsMap(fieldValue);
                    }
                }
                fieldsAsMap.put(fieldName, fieldValue);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return fieldsAsMap;
    }


}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class ReflectionUtilsTest extends AbstractTestCase {

    //。。。。。。

    @Test
    public void testGetCallerClassNamePerformance() {

        for (int i = 0; i < 6; i++) {
            int times = (int) Math.pow(10 + .0, i + .0);
            testGetCallerClassNameInSunJVMPerformance(times);
            testGetCallerClassNameInGeneralJVMPerformance(times);
            System.out.println();
        }
    }

    private void testGetCallerClassNameInSunJVMPerformance(int times) {
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < times; i++) {
            ReflectionUtils.getCallerClassNameInSunJVM();
        }
        long costTime = System.currentTimeMillis() - startTime;
        System.out.printf("It's cost to execute ReflectionUtils.getCallerClassNameInSunJVM() %d times : %d ms!\n", times, costTime);
    }

    private void testGetCallerClassNameInGeneralJVMPerformance(int times) {
        long startTime = System.currentTimeMillis();
        for (int i = 0; i < times; i++) {
            ReflectionUtils.getCallerClassNameInGeneralJVM();
        }
        long costTime = System.currentTimeMillis() - startTime;
        System.out.printf("It's cost to execute ReflectionUtils.getCallerClassNameInGeneralJVM() %d times : %d ms!\n", times, costTime);
    }

    // 。。。。
}


1
2
3
//,......
It's cost to execute ReflectionUtils.getCallerClassNameInSunJVM() 100000 times : 34 ms!
It's cost to execute ReflectionUtils.getCallerClassNameInGeneralJVM() 100000 times : 4016 ms!
区别

sun.reflect.Reflection 内部 的 #getCallerClass 方法

为什么异常会特别的费时间。

主要是在

Throwable#fillInStackTrace

1
private native Throwable fillInstackTrace(int dummy);

sun.misc.Unsafe -> VariableHandle

  • 计算偏移量
1
2
3
4
@ForceInline
public void putObject(Object o, long offset, Object x) {
    theInternalUnsafe.putObject(o, offset, x);
}

稍有不慎,JVM 就可能挂掉了。

VarHandle 用法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
private static void testVarHandle() throws NoSuchFieldException, IllegalAccessException {
    A a = new A();

    VarHandle varHandle;

    varHandle = MethodHandles.lookup()
        .in(A.class)
        .findVarHandle(A.class, "value", String.class);


    // CAS = 首先比较对等性,然后才能设置
    varHandle.compareAndSet(a, "Hellxx", "World");
    System.out.println(a.value);

    varHandle.compareAndSet(a, "Hello", "World");
    System.out.println(a.value);
}

统一日志 API (Platform Logging API)

  • Apache commons-logging : facade API for Java Logging And Log4j
  • Slf-api : java logging + log4j + logback
  • Java 9 : System.Logger 它想把其他的给统一掉,还想模块化。

Slf-api 没有把 Log4j2 搞进去


  • Spring Framework < 5.0 : Commons-logging
  • Spring Framework >- 5.0 : Slf4j-api
  • Spring Framework > 6 : Java 9 Logger 可能,猜测的。

自旋等待提示(Spin-Wait Hints)

As a practical example and use case, current x86 processors support a PAUSE instruction that can be used to indicate spinning behavior. Using a PAUSE instruction demonstrably reduces thread-to-thread round trips. Due to its benefits and widely recommended use, the x86 PAUSE instruction is commonly used in kernel spinlocks, in POSIX libraries that perform heuristic spins prior to blocking, and even by the JVM itself. However, due to the inability to hint that a Java loop is spinning, its benefits are not available to regular Java code.

作为一个实际示例和用例,当前 x86 处理器支持一个 PAUSE 指令,该指令可用于指示旋转行为。使用 PAUSE 指令可明显减少线程到线程的往返行程。由于其优点和广泛推荐的用途,x86 PAUSE 指令通常用于内核自旋锁、在阻止前执行启发式旋转的 POSIX 库中,甚至由 JVM 本身使用。但是,由于无法提示 Java 循环正在旋转,因此常规 Java 代码无法使用其优点。

img

An empty method would be a valid implementation of the java.lang.Thread.onSpinWait() method, but an intrinsic implementation is the obvious goal for hardware platforms that can benefit from it. We intend to produce an intrinsic x86 implementation for the JDK as part of this JEP. A prototype implementation already exists and results from initial testing show promise. Refer to JBS bug JDK-8147844 for pointers to webrevs with the proposed changes in class libraries and JVM.

空方法是 java 的有效实现。朗。线程。onSpinWait() 方法,但内在实现是硬件平台的明显目标,可以从中获益。作为 JEP 的一部分,我们打算为 JDK 生成一个内部 x86 实现。原型实现已经存在,初始测试的结果显示出希望。有关类库和 JVM 中建议的更改指向 Webrev 的指针,请参阅 JBS bug JDK-81478444。

java.lang.Thread#onSpinWait

1
2
    @HotSpotIntrinsicCandidate
    public static void onSpinWait() {}

就是,你调用一下,JVM 就知道了你要用 自旋锁了

压缩字符串(Compact String)

http://openjdk.java.net/jeps/254

在 Java 6 版本已经

  • Java6 里边都有了 -XX:+UserCompressedStrings 都已经做掉了,可以占用更少的内存