我有一个像这样的服务器:
class Server {
private WorkingThing worker;
public void init() {
runInNewThread({
// this will take about a minute
worker = new WorkingThing();
});
}
public Response handleRequest(Request req) {
if (worker == null) throw new IllegalStateException("Not inited yet");
return worker.work(req);
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,有线程处理请求和启动服务器的线程.请求可以在启动完成之前进入,因此有一个检查IllegalStateException.
现在,为了使这个线程安全(因此请求处理程序线程没有看到刚刚在init之后的陈旧的,null估计的版本worker),我必须使工作者易变,同步它,或者其他一些.
然而,在init完成之后,worker不会再次改变,所以它实际上是最终的.因此,似乎任何可能发生的锁争用都是浪费.那么,我能在这里做的最有效的事情是什么?
现在我知道它在实际意义上并不重要(读取网络请求的所有繁重工作等等,单个锁具有什么作用?),但我想知道是出于好奇.
Executor接口的Javadoc说明如下:
内存一致性影响:在将
Runnable对象提交到Executor执行开始之前发生的线程中的操作(可能在另一个线程中)。
Java 语言规范的哪一部分保证了这一点?或者仅仅是因为实现使用了一些内部同步?(如果是这样的话,一个例子就很好了。)那么在实现自定义时Executor我应该注意这个要求吗?
Java内存模型是否为Thread Pool交互提供了先前发生的保证?特别是,在工作队列中运行项目结束之前由线程池工作线程进行的写入是否会在之后从队列中运行下一个项目的工作线程可见?
规范(我个人觉得这个常见问题解答很有用:http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#synchronization)声明"对a的调用start()线程在启动线程中的任何操作之前发生. "或者简单地说,在启动线程之前所做的任何内存写入都将在执行之前执行并且对run()方法可见.对于线程池,它是不同的,start()通常在您进行写入之前运行.考虑一个简单的工作流,其中上下文对象被变异并传递给下一个动作:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Main {
private static class Container<T> {
private T value;
public T get() {
return value;
}
public void set(T newValue) {
value = newValue;
}
}
public static void main(String[] args) {
final Container<Integer> sharedObject = new Container<>();
final ExecutorService executor = Executors.newFixedThreadPool(10);
// SKIPPED: pre-warm the executor so all worker threads are start()'ed
final Runnable read = () -> System.out.println("Got " + …Run Code Online (Sandbox Code Playgroud) 有多个代码示例假定以下指令(1)和(2)不能重新排序:
int value;
volatile boolean ready;
// ...
value = 1; // (1)
ready = true; // (2)
Run Code Online (Sandbox Code Playgroud)
后一个 Stack Overflow 答案是指 JLS §17.4.5:
如果 x 和 y 是同一线程的动作,并且 x 在程序顺序中排在 y 之前,则 hb(x, y)。
但是我不明白为什么这应该适用于这里,因为 JLS示例 17.4-1还指出:
[...] 允许编译器重新排序任一线程中的指令,前提是这不会影响该线程的单独执行。
这显然是这里的情况。
JLS 中特定于的所有其他定义volatile仅针对相同的 volatile 变量,而不针对其他操作:
对 volatile 字段(第 8.3.1.4 节)的写入发生在该字段的每次后续读取之前。
在人们看到 volatile (读或写)的使用可能不会重新排序的保证时,我感到困惑。
您能否将您的解释基于 JLS 或基于 JLS 的其他来源。
According to Java Concurrency in Practice, it is dangerous to start a thread within a class constructor. The reason is that this exposes the this pointer to another thread before the object is fully constructed.
Despite this topic being discussed in many previous StackOverflow questions, I am still having difficulty understanding why this is such a concern. In particular, I hope to seek clarity on whether starting a thread inside a constructor can lead to memory consistency problems from …
以下代码是线程安全的吗?如果是这样,什么保证将ByteBuffer实例安全发布到执行 的线程CompletionHandler?
AsynchronousSocketChannel channel = ...
ByteBuffer buf = ByteBuffer.allocate(1024);
channel.read(buf, null, new CompletionHandler<Integer, Void>() {
//"completed" can be executed by a different thread than channel.read()
public void completed(Integer result, Void attachment) {
buf.flip(); //Can buf be safely accessed here? If so, why?
//...
}
public void failed(Throwable exc, Void attachment) {
//...
}
});
Run Code Online (Sandbox Code Playgroud) 让我们保存一下,我有这段代码,它显示线程读取过时的缓存,这会阻止它退出 while 循环。
class MyRunnable implements Runnable {
boolean keepGoing = true; // volatile fixes visibility
@Override public void run() {
while ( keepGoing ) {
// synchronized (this) { } // fixes visibility
// Thread.yield(); // fixes visibility
System.out.println(); // fixes visibility
}
}
}
class Example {
public static void main(String[] args) throws InterruptedException{
MyRunnable myRunnable = new MyRunnable();
new Thread(myRunnable).start();
Thread.sleep(100);
myRunnable.keepGoing = false;
}
}
Run Code Online (Sandbox Code Playgroud)
我相信Java内存模型保证对易失性变量的所有写入与任何线程的所有后续读取同步,从而解决了问题。
如果我的理解是正确的,同步块生成的代码也会清除所有挂起的读取和写入,这充当一种“内存屏障”并解决问题。
从实践中我发现插入yield并且println还使变量更改对线程可见并且它正确退出。我的问题是:
Yield/println/io 作为 JMM 以某种方式保证的内存屏障,还是幸运的副作用,无法保证有效? …
这里:
当对象的构造函数完成时,该对象被认为已完全初始化。仅在对象完全初始化后才能看到对该对象的引用的线程保证看到该对象的最终字段的正确初始化值。
现场是否有同样的保证volatile?如果y下面的例子中的字段是volatile我们可以观察到的呢0?
class FinalFieldExample {
final int x;
int y;
static FinalFieldExample f;
public FinalFieldExample() {
x = 3;
y = 4;
}
static void writer() {
f = new FinalFieldExample();
}
static void reader() {
if (f != null) {
int i = f.x; // guaranteed to see 3
int j = f.y; // could see 0
}
}
Run Code Online (Sandbox Code Playgroud)
}
我无法理解JSR-133 Coookbook中StoreLoad屏障的定义.
商店1; StoreLoad; 负载2
StoreLoad障碍使用Store1的数据值而不是从较新的存储到不同处理器执行的相同位置的数据值不正确地防止后续加载.
这是否意味着没有StoreLoad屏障,处理器可以将Store1存储到其写入缓冲区并从其写入缓冲区加载此存储的值,即使某些其他处理器对同一内存位置进行写入并刷新以在Store1和LOAD1?
java concurrency multithreading cpu-architecture java-memory-model
是否可以保证在线程持有其监视器时不会对对象进行垃圾回收?
例如
class x {
private WeakReference<Object> r;
Object getMonitorObject() {
Object o = new Object();
r = new WeakReference<>(o);
return o;
}
void thread1() throws Exception {
synchronized (getMonitorObject()) {
Thread.sleep(3000);
}
}
void thread2() {
Object b = r.get();
}
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,是否有任何保证在另一个线程正在休眠时b被非nullif thread2()调用thread1()?让我们假设整个过程thread2()是thread1()在另一个线程中休眠时执行的。