我对这个关于线程的任务有点困惑:我有三个类:
- 存储整数的类,我们称之为
StoredInteger
- 一个 Thread 类 (
IncrementThread
),用于递增StoredInteger
类的整数值 - 另一个线程类 (
ReadThread
),应该从StredInteger
类读取整数值
该过程应该以输出应该同步的方式进行,例如:
IncementThread
将值 1 写入StoredInteger
ReadThread
从StoredInteger
读取值 1IncementThread
将值 2 写入StoredInteger
ReadThread
从StoredInteger
读取值 2 ...等等
我遇到的问题是 ReadThread 等待 IncrementThread 完成,然后它只读取最后一个值。这是我的一些代码:
public class ReadThread extends Thread {
private StoredInteger stored_integer;
...
@Override
public void run()
{
int i = 0;
while(i < 100)
{
synchronized(this.getStoredInteger())
{
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
...
}
System.out.format("%s: Reading %d from StoredInteger\n", this.getClass().getSimpleName(), this.getStoredInteger().getValue());
i++;
}
}
}
...
}
.
public class IncrementThread extends Thread {
private StoredInteger stored_integer;
...
@Override
public void run()
{
int i = 0;
while(i < 100)
{
synchronized(this.getStoredInteger())
{
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
...
}
System.out.format("%s: Writing %d to StoredInteger\n", this.getClass().getSimpleName(), i);
this.getStoredInteger().setValue(i);
i++;
}
}
}
...
}
以及正在运行的线程:
public static void main(String[] args) throws InterruptedException
{
StoredInteger intgr = new StoredInteger();
Thread write = new Thread(new IncrementThread(intgr));
Thread read = new Thread(new ReadThread(intgr));
write.start();
read.start();
write.join();
read.join();
}
我在这里做错了什么?
谢谢!
最佳答案
代码中没有任何内容可以保证读/写线程交替工作。基本上,两个线程都进入互斥区域。他们在那里等待 1 秒(保持锁定)并写入或读取一个值。您可以在互斥体区域之外进行 sleep ,但同样,它不能保证线程会交替工作(尽管使用 1 秒的 sleep() 几乎可以肯定它们会交替工作)。
@Override
public void run() {
int i = 0;
while (i < 100) {
synchronized (stored_integer) {
System.out.format("%s: Writing %d to StoredInteger\n", this.getClass().getSimpleName(), i);
stored_integer.value = i;
i++;
}
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
//
}
}
}
@Override
public void run() {
int i = 0;
while (i < 100) {
synchronized (stored_integer) {
System.out.format("%s: Reading %d from StoredInteger\n", this.getClass().getSimpleName(), stored_integer.value);
i++;
}
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
}
}
但是,要正确执行此操作,您需要使用 wait() 和 notification() 方法。让写入器线程在写入后等待,以便读取器线程可以读取并唤醒写入器。像这样的事情:
@Override
public void run() {
int i = 0;
while (i < 100) {
synchronized (stored_integer) {
System.out.format("%s: Writing %d to StoredInteger\n", this.getClass().getSimpleName(), i);
stored_integer.value = i;
i++;
// Writer wakes up writer
stored_integer.notify();
// Writer waits until it can read
try {
stored_integer.wait();
} catch (InterruptedException ex) {
//
}
}
}
}
@Override
public void run() {
synchronized (stored_integer) {
// Reader waits for the first time!
try {
stored_integer.wait();
} catch (InterruptedException ex) {
//
}
}
int i = 0;
while (i < 100) {
synchronized (stored_integer) {
System.out.format("%s: Reading %d from StoredInteger\n", this.getClass().getSimpleName(), stored_integer.value);
i++;
// Reader wakes up writer
stored_integer.notify();
// If there are still more values to read
if (i < 100) {
// Reader waits until it can read
try {
stored_integer.wait();
} catch (InterruptedException ex) {
//
}
}
}
}
}
在主线程上,首先在读取器线程上使用 start(),然后才在写入器线程上使用 start()。即使这样,代码也可能无法工作。如果您的处理器不应该在编写器执行 Notify() 之前等待读取器(这可能会发生,因为毕竟这些是线程),那么您将陷入死锁。解决这个问题的一种方法是使用一个条件变量,它会在其中等待(如果需要),并且仅在读取器被阻塞等待后才启动写入器线程。
关于Java线程: synchronized reading and writing of value on the same object,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24520129/