我正在使用静态代码块来初始化我所拥有的注册表中的某些控制器.因此,我的问题是,我可以保证这个静态代码块只在首次加载类时才会被调用一次吗?我知道我无法保证何时会调用此代码块,我猜它是在Classloader首次加载它时.我意识到我可以在静态代码块中同步类,但我的猜测实际上这是怎么回事?
简单的代码示例是;
class FooRegistry {
static {
//this code must only ever be called once
addController(new FooControllerImpl());
}
private static void addController(IFooController controller) {
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
或者我应该这样做;
class FooRegistry {
static {
synchronized(FooRegistry.class) {
addController(new FooControllerImpl());
}
}
private static void addController(IFooController controller) {
// ...
}
}
Run Code Online (Sandbox Code Playgroud) java static multithreading synchronization static-initializer
我需要在代码块中使用流中的'n'项然后完成,实质上:
public static <T> void eat(Stream<T> stream, int n)
// consume n items of the stream (and throw them away)
}
Run Code Online (Sandbox Code Playgroud)
在我的情况下,我无法改变签名返回Stream<T>简单return stream.skip(n); 我必须实际丢弃流中的一些元素(不是简单的逻辑) - 为下游消费者做好准备,这不需要知道这是怎么发生的,甚至不知道发生了什么.
最简单的方法是使用limit(n),但我必须调用流终止方法来激活流,所以本质上我有:
public static <T> void skip(Stream<T> stream, int n) {
stream.limit(n).forEach(t -> {});
}
Run Code Online (Sandbox Code Playgroud)
注意:此代码完全简化了实际代码,仅用于说明目的.实际上,限制将不起作用,因为存在围绕什么/如何消耗元素的逻辑.可以把它想象成从流中消费"header"元素,然后让消费者使用"body"元素.
这个问题是关于"无所事事"的lambda t -> {}.
在JDK中的某个地方是否有"无所事事"的消费者,比如"无所事事"功能Function.identity()?
注意:这是不是重复,请仔细阅读题目сarefully /sf/users/241389361/报价:
真正的问题是为什么代码有时会起作用.即使没有lambdas,问题也会重现.这让我觉得可能存在JVM错误.
在/sf/answers/3759645221/的评论中,我试图找出原因,为什么代码的行为从一个开始到另一个不同,并且该讨论的参与者给了我一些建议来创建一个单独的主题.
不要考虑以下源代码:
public class Test {
static {
System.out.println("static initializer: " + Thread.currentThread().getName());
final long SUM = IntStream.range(0, 5)
.parallel()
.mapToObj(i -> {
System.out.println("map: " + Thread.currentThread().getName() + " " + i);
return i;
})
.sum();
}
public static void main(String[] args) {
System.out.println("Finished");
}
}
Run Code Online (Sandbox Code Playgroud)
有时(几乎总是)它会导致死锁.
输出示例:
static initializer: main
map: main 2
map: ForkJoinPool.commonPool-worker-3 4
map: ForkJoinPool.commonPool-worker-3 3
map: ForkJoinPool.commonPool-worker-2 0
Run Code Online (Sandbox Code Playgroud)
但有时它会成功完成(非常罕见):
static initializer: main
map: main 2
map: main …Run Code Online (Sandbox Code Playgroud) 自从他引入Java 8以来,我真的迷上了lambdas,并且尽可能地开始使用它们,主要是为了开始习惯它们.最常见的用法之一是当我们想要迭代并对一组对象进行操作时,在这种情况下我要么求助于forEach或者stream().我很少写旧for(T t : Ts)循环,我差点忘了for(int i = 0.....).
然而,我们前几天与我的主管讨论过这个问题,他告诉我,lambdas并不总是最好的选择,有时会阻碍性能.从我在这个新功能上看过的一个讲座中我感觉lambda迭代总是被编译器完全优化,并且(总是?)比裸迭代更好,但他不同意.这是真的?如果是,我如何区分每种方案中的最佳解决方案?
PS:我不是在谈论建议申请的案例parallelStream.显然那些会更快.
我使用invokeAndWait偶然发现了一个问题.下面的示例代码说明了该问题.任何人都可以详细说明发生了什么事吗?为什么lambda表达式挂起而匿名内部类和方法ref没有.
public class Test {
// A normal (non-static) initializer does not have the problem
static {
try {
System.out.println("initializer start");
// --- Works
System.out.println("\nanonymous inner-class: Print.print");
EventQueue.invokeAndWait(new Runnable() {
@Override
public void run() {
Print.print();
}
});
// --- Works
System.out.println("\nmethod ref: Print.print");
EventQueue.invokeAndWait(Print::print);
// --- Hangs forever
System.out.println("\nlambda: Print.print");
EventQueue.invokeAndWait(() -> Print.print());
System.out.println("\ninitializer end");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new Test();
}
}
Run Code Online (Sandbox Code Playgroud)
Print类:
public class Print {
public …Run Code Online (Sandbox Code Playgroud) 代码如下,在Main方法中我调用静态方法:
public class Main {\n public static void main(String[] args) {\n MyFactory.getSomething();\n System.out.println("over"); \n }\n}\nRun Code Online (Sandbox Code Playgroud)\n在静态方法中,让主线程等待,然后由demo线程唤醒。但是主线程没有唤醒,我不知道为什么。
\nimport java.util.concurrent.TimeUnit;\n\npublic class MyFactory {\n private static Object lock = new Object();\n\n static{\n init();\n }\n\n private static void init(){\n new Thread(()->{\n try {\n // make this thread run after main thread\n TimeUnit.SECONDS.sleep(3);\n System.out.println("task run...");\n synchronized (lock){\n lock.notifyAll(); // notify main thread\n }\n } catch (InterruptedException e) {\n throw new RuntimeException(e);\n }\n },"demo-thread").start();\n\n synchronized (lock){\n try {\n System.out.println("waiting...");\n …Run Code Online (Sandbox Code Playgroud) 以下代码导致死锁(在我的电脑上):
public class Test {
static {
final int SUM = IntStream.range(0, 100)
.parallel()
.reduce((n, m) -> n + m)
.getAsInt();
}
public static void main(String[] args) {
System.out.println("Finished");
}
}
Run Code Online (Sandbox Code Playgroud)
但是,如果我reduce用匿名类替换lambda参数,它不会导致死锁:
public class Test {
static {
final int SUM = IntStream.range(0, 100)
.parallel()
.reduce(new IntBinaryOperator() {
@Override
public int applyAsInt(int n, int m) {
return n + m;
}
})
.getAsInt();
}
public static void main(String[] args) {
System.out.println("Finished");
}
}
Run Code Online (Sandbox Code Playgroud)
你能解释一下这种情况吗?
我发现代码(与以前有点不同):
public class …Run Code Online (Sandbox Code Playgroud) PS: Sorry for my poor english.I can't describe the problem clearly. :(
When I don't use the "lambda method reference" code style in the static block, like:
static{
map.keySet().parallelStream().forEach(e -> {
System.out.println(e);
});
}
Run Code Online (Sandbox Code Playgroud)
then the program running forever, never stop.
But when I change the code to
static{
map.keySet().parallelStream().forEach(System.out::println);
}
Run Code Online (Sandbox Code Playgroud)
然后该错误消失了。该程序可以立即完成。
请直接看一下代码,我已经尽力简化了代码。
public class BugSimulate {
static {
init();
}
private static void init() {
Map<Integer, String> map = new HashMap<>();
int i = 0;
map.put(++i, "1");
map.put(++i, "1"); …Run Code Online (Sandbox Code Playgroud) java ×8
java-8 ×3
jvm ×3
lambda ×3
deadlock ×2
java-stream ×2
classloader ×1
concurrency ×1
consumer ×1
forkjoinpool ×1
iteration ×1
jvm-crash ×1
jvm-hotspot ×1
static ×1
swing ×1