我正在尝试解决一个简单的问题,并陷入Java内存模型兔子洞.
什么是最简单和/或最有效(判断调用此处),但无竞争(根据JMM精确定义)编写包含非最终引用字段的Java类的方法,该字段初始化为非空值构造函数,后来从未改变过,这样任何其他线程的后续访问都不能看到非空值?
破碎的起始示例:
public class Holder {
private Object value;
public Holder(Object value) {
if (value == null)
throw NullPointerException();
this.value = value;
}
public Object getValue() { // this could return null!
return this.value;
}
}
Run Code Online (Sandbox Code Playgroud)
而根据这篇文章,标记该领域volatile甚至不起作用!
public class Holder {
private volatile Object value;
public Holder(Object value) {
if (value == null)
throw NullPointerException();
this.value = value;
}
public Object getValue() { // this STILL could return null!!
return this.value;
}
} …Run Code Online (Sandbox Code Playgroud) 考虑这个程序:
import java.util.regex.Pattern;
public class xx {
/*
* Ñ
* LATIN CAPITAL LETTER N WITH TILDE
* Unicode: U+00D1, UTF-8: C3 91
*/
public static final String BIG_N = "\u00d1";
/*
* ñ
* LATIN SMALL LETTER N WITH TILDE
* Unicode: U+00F1, UTF-8: C3 B1
*/
public static final String LITTLE_N = "\u00f1";
public static void main(String[] args) throws Exception {
System.out.println(BIG_N.equalsIgnoreCase(LITTLE_N));
System.out.println(Pattern.compile(BIG_N, Pattern.CASE_INSENSITIVE).matcher(LITTLE_N).matches());
}
}
Run Code Online (Sandbox Code Playgroud)
由于Ñ是ñ的大写版本,你可以期望它打印:
true
true
Run Code Online (Sandbox Code Playgroud)
但它实际打印的内容(java 1.7.0_17-b02)是:
true
false
Run Code Online (Sandbox Code Playgroud)
为什么?
为什么这个java程序不能编译:
public class xx {
public static final Object obj;
static {
// obj = null; // this compiles
xx.obj = null; // this doesn't
}
}
Run Code Online (Sandbox Code Playgroud)
有这个错误:
$ javac xx.java
xx.java:5: cannot assign a value to final variable obj
xx.obj = null; // this doesn't
^
1 error
$ javac -version
javac 1.6.0_33
Run Code Online (Sandbox Code Playgroud)
的时候,如果我取代xx.obj = null用obj = null(如评论提到),它编译.
我认为xx.类名前缀或多或少只是语法...这是编译器或语言规范中的错误吗?:)
假设我们有一个这样的类:
public class xx {
public interface Foo<T> {
T getValue();
void setValue(T value);
}
public void resetFoos(Iterable<Foo<?>> foos) {
for (Foo<?> foo : foos)
foo.setValue(foo.getValue());
}
}
Run Code Online (Sandbox Code Playgroud)
它将无法编译,即使直观地看起来它应该"应该":
xx.java:10: setValue(capture#496 of ?) in xx.Foo<capture#496 of ?> cannot be applied to (java.lang.Object)
foo.setValue(foo.getValue());
Run Code Online (Sandbox Code Playgroud)
原因是foo没有绑定泛型类型,因此编译器不"知道"输出foo.getValue()与输入兼容foo.setValue().
所以要解决这个问题,你必须创建一个新方法,只是为了在for()循环中绑定泛型类型参数:
public class xx {
public interface Foo<T> {
T getValue();
void setValue(T value);
}
public void resetFoos(Iterable<Foo<?>> foos) {
for (Foo<?> foo : foos)
this.resetFoo(foo);
}
// …Run Code Online (Sandbox Code Playgroud) MySQL 5.5.28.我有两个表Person,Message后者有一个外键给前者.每个表都有id主键列,Person表中还有一个personId(唯一)索引的列.
下面的查询应该利用personId密钥索引,但是MySQL需要扫描整个Message表,原因如下:
mysql> EXPLAIN SELECT `m`.*
-> FROM
-> `Message` AS `m`
-> LEFT JOIN
-> `Person` AS `p` ON (`m`.`person` = `p`.`id`)
-> WHERE
-> 'M002649397' IS NULL OR
-> `p`.`personId` = 'M002649397';
+----+-------------+-------+--------+---------------+---------+---------+----------------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+----------------+--------+-------------+
| 1 | SIMPLE | m | ALL … 我的简单目标:监视Java应用程序的内存使用情况,以便在应用程序危险地接近抛出时,可以收到警告OutOfMemoryError.
是的,简单说明,但提出正确的解决方案似乎非常复杂.一些复杂因素是:
OutOfMemoryError:
permgen空间,它有它自己的大小限制(通过设置-XX:MaxPermSize=)-Xmx)OutOfMemoryError.System.gc()保证VM将回收所有可能可回收的对象(未引用和/或弱引用的对象),那将是很好的,但事实并非如此.所以调用System.gc()然后Runtime.freeMemory()不可靠.那么回答这个问题的好方法是OutOfMemoryError什么呢?我的Java应用程序是否可以投入?
换句话说,假设应用程序版本X运行良好且没有内存泄漏,但版本X + 1具有缓慢的无法识别的内存泄漏.我希望在版本X + 1抛出之前通过此监视发出警报OutOfMemoryError,但我希望完全相同的监视不会给版本X带来误报.设置此监视可能需要一些调整 - 这没关系.
一个可能的答案可能是这样的结果:在GC运行之后,堆栈利用率在过去的N次"完整"GC运行中的最大值是多少?如果此值超过总分配内存的X%,则发出警报声.
这个想法是确定"应用程序内存使用"的简单数字,如百分比,甚至像LOW,MEDIUM或HIGH,然后监视此值.
该jstat命令给出了大量的相关资料,问题就沸腾它归结为一个简单的答案,并避免由于上面列出的复杂因素误报(或否定).
接口:
interface PublicCloneable {
Object clone();
}
interface HasPosition {
// doesn't matter
}
Run Code Online (Sandbox Code Playgroud)
尝试使用交集类型:
@SuppressWarnings("unchecked")
<E extends PublicCloneable & HasPosition> E cloneAndIncrementPosition(E elem) {
final E clone = (E)elem.clone();
// rest omitted
}
Run Code Online (Sandbox Code Playgroud)
尝试编译javac 1.8.0_60:
$ javac xx.java
xx.java:13: error: clone() in Object cannot implement clone() in PublicCloneable
<E extends PublicCloneable & HasPosition> E cloneAndIncrementPosition(E elem) {
^
attempting to assign weaker access privileges; was public
xx.java:14: error: clone() has protected access in Object
final E clone …Run Code Online (Sandbox Code Playgroud) 我如何得到MethodHandle像数组构造函数int[]::new?
这不起作用:
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.publicLookup();
MethodHandle mh = lookup.findConstructor(int[].class, MethodType.methodType(void.class, int.class));
System.out.println(mh);
System.out.println(mh.invoke());
}
Run Code Online (Sandbox Code Playgroud)
结果如下:
Exception in thread "main" java.lang.NoSuchMethodException: no such constructor: [I.<init>(int)void/newInvokeSpecial
at java.lang.invoke.MemberName.makeAccessException(MemberName.java:871)
at java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:990)
at java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:1382)
at java.lang.invoke.MethodHandles$Lookup.findConstructor(MethodHandles.java:920)
at xx.main(xx.java:11)
Caused by: java.lang.NoSuchMethodError: java.lang.Object.<init>(I)V
at java.lang.invoke.MethodHandleNatives.resolve(Native Method)
at java.lang.invoke.MemberName$Factory.resolve(MemberName.java:962)
at java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:987)
... 3 more
Run Code Online (Sandbox Code Playgroud)
这也不是:
public static void main(String[] args) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.publicLookup();
MethodHandle mh = lookup.findConstructor(int[].class, MethodType.methodType(void.class));
System.out.println(mh); …Run Code Online (Sandbox Code Playgroud) 考虑这个(完全人为的)Java代码:
final List<Integer> s = Arrays.asList(1, 2, 3);
final int[] a = new int[1];
a[0] = 100;
s.parallelStream().forEach(i -> {
synchronized (a) {
a[0] += i;
}
});
System.out.println(a[0]);
Run Code Online (Sandbox Code Playgroud)
此代码是否保证输出"106"?
似乎不存在,除非有一个先发生过的关系建立起来parallelStream(),通过它我们可以肯定地知道a[0]lambda 中的第一次访问将看到100而不是零(根据我对Java内存模型的理解).
但Collection.parallelStream()没有记录建立这种关系......
可以询问完成parallelStream()方法调用的相同问题.
所以我错过了一些东西,或者为了正确性,上述代码需要看起来像这样:
final List<Integer> s = Arrays.asList(1, 2, 3);
final int[] a = new int[1];
synchronized (a) {
a[0] = 100;
}
s.parallelStream().forEach(i -> {
synchronized (a) {
a[0] += i;
}
});
synchronized (a) …Run Code Online (Sandbox Code Playgroud) 考虑这个程序:
public class xx<T> {
<T> Iterable<T> createIterable(Class<T> cls) {
return null;
}
Iterable<? extends Number> createNumberIterable(boolean floatingPoint) {
return this.createIterable(floatingPoint ? Integer.class : Float.class);
}
}
Run Code Online (Sandbox Code Playgroud)
在Java 7下,它编译:
$ java -version
java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)
$ javac xx.java
$
Run Code Online (Sandbox Code Playgroud)
在Java 8下它没有:
$ java -version
java version "1.8.0_40"
Java(TM) SE Runtime Environment (build 1.8.0_40-b25)
Java HotSpot(TM) 64-Bit Server VM (build 25.40-b25, mixed mode)
$ javac xx.java …Run Code Online (Sandbox Code Playgroud) 我对这个程序的输出感到有些神秘:
public class xx {
public static void main(String[] args) throws Exception {
Number x = false ? new Long(123) : new Integer(456);
System.out.println(x + " isa " + x.getClass().getName());
}
}
Run Code Online (Sandbox Code Playgroud)
这是它输出的内容:
456 isa java.lang.Long
Run Code Online (Sandbox Code Playgroud)
它出现在编译器"促进"类型的对象Integer来Long,就像它通常会促进原始值.我从来没有听说过对象推广,这种行为似乎非常令人惊讶.
我的问题:根据JLS,这是非常正确的行为吗?如果是这样,我希望尽可能看到参考.
或者这是一种autoboxing-gone-wild编译器错误?
我正在使用:
java version "1.8.0_60"
Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)
Run Code Online (Sandbox Code Playgroud) 运行这个程序:
import java.text.*;
import java.util.*;
public class xx {
public static void main(String[] args) throws Exception {
final SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US);
format.setLenient(false);
format.parse("Tue, 16 Jan 2010 04:41:09 -0000");
}
}
Run Code Online (Sandbox Code Playgroud)
给出这个结果(java version "1.7.0_17"):
Exception in thread "main" java.text.ParseException: Unparseable date: "Tue, 16 Jan 2010 04:41:09 -0000"
at java.text.DateFormat.parse(DateFormat.java:357)
at xx.main(xx.java:7)
Run Code Online (Sandbox Code Playgroud)
看来,当设置为非宽松模式时,Tue,前缀是无法解析的.
问题是,为什么EEE,不能匹配Tue,日期字符串的前缀?
Java很久,第一次使用C++.
我正在编写一个包装现有C++ API的Java类,看起来像这样:
public class Foo implements Closeable {
private long handle;
public Foo(File file) {
this.handle = Foo.openFile(file.toString());
}
// other methods go here...
public void close() {
Foo.closeFile(this.handle);
this.handle = 0;
}
private static native long openFile(String file);
private static native void closeFile(long handle);
}
Run Code Online (Sandbox Code Playgroud)
我们将指向本机C++对象的指针填充到handle字段中.
问题是C++库没有给我一个指针,它给了我一个unique_ptr<Foo>.所以这必须被移到堆上openFile()(因此它不会超出范围),然后被销毁closeFile().
我无法让这个工作,我不确定我是否正确地做到了.在C++中正确执行此操作的最简单/最简洁的方法是什么?
这是我目前正在做的事情:
// This holds a unique_ptr<T>, typically on the heap, until no longer needed
template <class T>
class PointerHolder {
public:
PointerHolder(unique_ptr<T> …Run Code Online (Sandbox Code Playgroud) java ×11
javac ×3
jls ×2
c++ ×1
date ×1
generics ×1
heap ×1
java-8 ×1
java-stream ×1
methodhandle ×1
mysql ×1
regex ×1
unique-ptr ×1