当整数生成时,消费者线程对它们的值求和(1+2+3...+10=55)
生产者线程生成从 1 到 10 的整数
该程序旨在生成一个整数并立即使用它。但是,在程序结束时生成的结果很少等于 55。这是因为线程不会等待彼此完成其任务
需要向代码添加同步,以便使用者线程仅在生产者线程生成新整数后才向总数添加一个值
驱动程序.java
public class Lab08_Driver {
public static void main(String args[]) {
UsingSharedInt h = new UsingSharedInt();
Producer p = new Producer(h);
Consumer c = new Consumer(h);
p.start();
c.start();
}
}
消费者.java
public class Consumer extends Thread {
private UsingSharedInt cHold;
public Consumer( UsingSharedInt h )
{
super( "ConsumeInteger" );
cHold = h;
}
public void run()
{
int val, sum = 0;
do {
// sleep for a random interval
try {
Thread.sleep( (int) ( Math.random() * 3000 ) );
}
catch( InterruptedException e ) {
System.err.println( e.toString() );
}
val = cHold.getSharedInt();
sum += val;
} while ( val != 10 );
System.err.println(
getName() + " retrieved values totaling: " + sum +
"nTerminating " + getName() );
}
}
制片人.java
public class Producer extends Thread {
private UsingSharedInt pHold;
public Producer( UsingSharedInt h )
{
super( "ProduceInteger" );
pHold = h;
}
public void run()
{
for ( int count = 1; count <= 10; count++ ) {
// sleep for a random interval
try {
Thread.sleep( (int) ( Math.random() * 3000 ) );
}
catch( InterruptedException e ) {
System.err.println( e.toString() );
}
pHold.setSharedInt( count );
}
System.err.println( getName() +
" finished producing values" +
"nTerminating " + getName() );
}
}
使用共享.java
// HoldIntegerUnsynchronized.java
public class UsingSharedInt {
private int sharedInt = -1;
public void setSharedInt( int val )
{
System.err.println( Thread.currentThread().getName() +
" setting sharedInt to " + val );
sharedInt = val;
}
public int getSharedInt()
{
System.err.println( Thread.currentThread().getName() +
" retrieving sharedInt value " + sharedInt );
return sharedInt;
}
}
只需将 BlockingQueue
用作生产者产生和消费者消费的元素的容器:
public class UsingSharedInt {
private BlockingQueue<Integer> q = new ArrayBlockingQueue<>(100);
public void setSharedInt( int val )
{
System.err.println( Thread.currentThread().getName() +
" setting sharedInt to " + val );
q.add(val); // puts val into the queue
}
public int getSharedInt()
{
int val = q.take(); // waits for element to become available in queue, then returns one
System.err.println( Thread.currentThread().getName() +
" retrieving sharedInt value " + val);
return val;
}
}
问题不仅在于对共享 int 的并发访问。有一些排队逻辑需要查看。
在代码中,Producer
循环并设置 SharedInt
的值,而无需等待Consumer
使用它。当Consumer
读取一个值时,它将读取 [1,10] 之间的一些值,当然还有最后一个 (10),因为它是 while 循环中的退出条件。但是由于每个线程都是随机时间写入/读取值,因此您将不会有完美的写入/读取/写入/读取/等序列,而是像
为了使其正常工作,您需要在设置一个值后阻止SharedInt
中的写入(或者您需要对不同的值进行排队),直到该值被Consumer
线程读取(使用)。Consumer
读取也是如此,必须等到生产者设置一个值。
实现此目的的最简单方法是使用并发集合(如 BlockingQueue
)来存储共享整数。请参阅文档中的生产者消费者示例。
您可以自己实现此队列机制来尝试低级同步,但这不仅仅是在SharedInt
周围放置一个synchronized
关键字的问题......
只需在 Consumer 中添加一个 temp int,看看它是否与上一个不同。
int val, sum, tmp = 0;
do {
// sleep for a random interval
try {
Thread.sleep( (int) ( Math.random() * 3000 ) );
}catch( InterruptedException e ) {
System.err.println( e.toString() );
}
val = cHold.getSharedInt();
if(val!=tmp){
sum += val;
}
tmp = val;
} while ( val != 10 );