Java指南中的并发问题

时间:2012-01-04 03:25:47

标签: java multithreading concurrency synchronization deadlock

所以我一直在阅读并发问题并且在路上有一些问题(guide I followed - 虽然我不确定它是否是最好的来源):

  1. 进程与线程:基本上,进程是整个程序,而线程可以是程序的(小)部分吗?
  2. 我不确定为什么会出现interrupt()方法和InterruptedException。为什么甚至要使用interrupted()方法?在我看来,Java只是增加了一个额外的间接层。
  3. 对于同步(特别是关于该链接中的那个),添加synchronize关键字如何解决问题?我的意思是,如果线程A返回其递增的c并且线程B返回递减的c并将其存储到其他变量,我不确定问题是如何解决的。我的意思是这可能是回答我自己的问题,但是应该假设在其中一个线程返回一个答案后,终止?如果是这种情况,为什么添加同步会产生影响呢?
  4. 我(从一些随机PDF中)读到,如果你有两个Threads start(),你不能保证第一个线程将在第二个线程之前发生。但是你怎么能保证呢?
  5. 在同步语句中,我不完全确定在方法中添加synchronized的重点是什么。把它拿出来有什么问题?是因为人们期望两者分别变异,而是一起获得?为什么不让两个非同步?
  6. volatile 只是变量的关键字,与synchronized?
  7. 同义
  8. 在死锁问题中,如何同步甚至帮助这种情况?是什么让这种情况与启动两个更改变量的线程不同?
  9. 此外,其他人的“等待”/锁定在哪里?我原以为bow()被封锁了,而不是bowBack()。
  10. 我会在这里停下来,因为我觉得如果我没有回答这些问题就进一步,我将无法理解后来的课程。

2 个答案:

答案 0 :(得分:4)

数目:

  1. 是的,进程是一个操作系统进程,它有一个地址空间,一个线程是一个执行单元,并且进程中可以有多个执行单元。
  2. interrupt()方法和InterruptedException通常用于唤醒等待让他们做某事或终止的线程。
  3. 同步是互斥或锁定的一种形式,是计算机编程中非常标准和必需的东西。谷歌这些条款并阅读,你会得到你的答案。
  4. 是的,这不能保证,你必须有一些机制,涉及线程用来确保它们以所需顺序运行的同步。这将特定于线程中的代码。
  5. 见#3
  6. 的回答
  7. Volatile是一种确保特定变量可以在不同线程之间正确共享的方法。在多处理器机器上(几乎每个人都有这些日子)​​必须确保变量的值在处理器之间是一致的。它实际上是一种同步单个值的方法。
  8. 以更一般的术语阅读有关死锁的内容以了解这一点。一旦你第一次理解互斥和锁定,你将能够理解死锁是如何发生的。
  9. 我没看过你读的材料,所以我不明白这个。遗憾。

答案 1 :(得分:2)

我发现用于解释同步和波动的例子是人为的,难以理解的目的。以下是我的首选示例:

<强>同步

private Value value;

public void setValue(Value v) {
  value = v;
}

public void doSomething() {
  if(value != null) {
    doFirstThing();
    int val = value.getInt(); // Will throw NullPointerException if another
                              // thread calls setValue(null);
    doSecondThing(val);
  }
}

如果在单线程环境中运行,上面的代码是完全正确的。但是,即使是2个线程,也有可能在检查和使用它之间更改value。这是因为方法doSomething() 不是原子

要解决此问题,请使用同步:

private Value value;
private Object lock = new Object();

public void setValue(Value v) {
  synchronized(lock) {
    value = v;
  }
}

public void doSomething() {
  synchronized(lock) { // Prevents setValue being called by another thread.
    if(value != null) {
      doFirstThing();
      int val = value.getInt(); // Cannot throw NullPointerException.
      doSecondThing(val);
    }
  }
}

<强>易失性:

private boolean running = true;

// Called by Thread 1.
public void run() {
  while(running) {
    doSomething();
  }
}

// Called by Thread 2.
public void stop() {
  running = false;
}

要解释这一点,需要了解Java内存模型。值得深入阅读,但这个例子的简短版本是Threads有自己的变量副本,这些变量只与同步块上的主内存同步,并且当达到volatile变量时。允许Java编译器(特别是JIT)将代码优化为:

public void run() {
  while(true) { // Will never end
    doSomething();
  }
}

要防止此优化,您可以将变量设置为volatile,这会强制线程在每次读取变量时访问主内存。请注意,如果您使用synchronized语句,则这是不必要的,因为两个关键字都会导致同步到主内存。

我没有像弗朗西斯那样直接解决你的问题。我希望这些示例能够以比您在Oracle教程中看到的示例更好的方式让您了解这些概念。