我正在研究Java 9中的新内在方法,现在发现方法SELECT DISTINCT p.Id, UNIX_TIMESTAMP(p.PostCreationTime) AS PostCreationTime, p.Content AS Content, p.Bu AS Bu, p.Se AS Se, UNIX_TIMESTAMP(p.PostCreationTime) AS PostTimeOrder
FROM Post p
WHERE (p.Id IN (SELECT pc.PostId
FROM PostCreator pc
WHERE (pc.UserId IN (SELECT uf.FollowedId
FROM UserFollowing uf
WHERE uf.FollowingId = '100')
OR pc.UserId = '100')
))
OR (p.Id IN (SELECT pum.PostId
FROM PostUserMentions pum
WHERE (pum.UserId IN (SELECT uf.FollowedId
FROM UserFollowing uf
WHERE uf.FollowingId = '100')
OR pum.UserId = '100')
))
OR (p.Id IN (SELECT ssp.PostId
FROM SStreamPost ssp
WHERE (ssp.SStreamId IN (SELECT ssf.SStreamId
FROM SStreamFollowing ssf
WHERE ssf.UserId = '100'))
))
OR (p.Id IN (SELECT psm.PostId
FROM PostSMentions psm
WHERE (psm.StockId IN (SELECT sf.StockId
FROM StockFollowing sf
WHERE sf.UserId = '100' ))
))
UNION ALL
SELECT DISTINCT p.Id AS Id, UNIX_TIMESTAMP(p.PostCreationTime) AS PostCreationTime, p.Content AS Content, p.Bu AS Bu, p.Se AS Se, UNIX_TIMESTAMP(upe.PostEchoTime) AS PostTimeOrder
FROM Post p
INNER JOIN UserPostE upe
on p.Id = upe.PostId
INNER JOIN UserFollowing uf
on (upe.UserId = uf.FollowedId AND (uf.FollowingId = '100' OR upe.UserId = '100'))
ORDER BY PostTimeOrder DESC;
is intrinsic以及Class.cast
。
我做了简单的基准测试来检查:
Class.isInstance
结果:
@BenchmarkMode(Mode.Throughput)
@Fork(1)
@State(Scope.Thread)
@Warmup(iterations = 10, time = 1, batchSize = 1000)
@Measurement(iterations = 20, time = 1, batchSize = 1000)
public class Casting {
public Object msg;
public Class<String> type;
@Setup
public void setup(BenchmarkParams params) {
type = String.class;
msg = "123";
}
@Benchmark
public boolean isInstanceMethod() {
return type.isInstance(msg);
}
@Benchmark
public boolean isInstanceMethodExplicit() {
return String.class.isInstance(msg);
}
@Benchmark
public boolean isInstanceRegular() {
return msg instanceof String;
}
@Benchmark
public String castMethod() {
return type.cast(msg);
}
@Benchmark
public String castMethodExplicit() {
return String.class.cast(msg);
}
@Benchmark
public String castRegular() {
return (String) msg;
}
}
ENV:
Benchmark Mode Cnt Score Error Units
Casting.castMethod thrpt 20 254604.793 ± 3863.859 ops/s
Casting.castMethodExplicit thrpt 20 336046.787 ± 10059.986 ops/s
Casting.castRegular thrpt 20 344369.229 ± 4855.492 ops/s
Casting.isInstanceMethod thrpt 20 325867.697 ± 6511.731 ops/s
Casting.isInstanceMethodExplicit thrpt 20 415387.363 ± 2993.788 ops/s
Casting.isInstanceRegular thrpt 20 396613.371 ± 16799.378 ops/s
结果似乎有些出乎意料。通过类变量调用它们时,# JMH version: 1.19
# VM version: JDK 9, VM 9+181
# VM invoker: /usr/lib/jvm/java-9-oracle/bin/java
和Class.cast
都会变慢。我的理解是内在应该使这种方法与替代方法一样快。
变量会破坏内在优化吗?或者这个开销是预期的吗?
答案 0 :(得分:6)
事实上,方法是内在的,而且它们对变量而不是常量的工作速度较慢。
考虑表达式Math.min(a, 2)
和Math.min(a, b)
。方法Math.min
在两种情况下都是固有的。但是,第一个表达式显然更快,因为不需要加载变量b
,编译器可以直接在cmp
指令中内联常量2。
isInstance/cast
方法也是如此。当type
不是常量时,JVM仍然需要加载变量,检查它是否为非空,然后从java.lang.Class
实例加载VM Klass指针。
您可以通过明确禁用内在函数来验证内在函数是否有效。在这种情况下,基准将多更慢。
@Benchmark
public String castMethod() {
return type.cast(msg);
}
@Benchmark
@Fork(jvmArgs = {
"-XX:+UnlockDiagnosticVMOptions",
"-XX:DisableIntrinsic=_Class_cast,_isInstance",
})
public String castMethodNoIntrinsic() {
return type.cast(msg);
}
结果:
Benchmark Mode Cnt Score Error Units
Casting.castMethod avgt 10 4,777 ± 0,065 ns/op
Casting.castMethodNoIntrinsic avgt 10 28,557 ± 0,124 ns/op