Java 并发求和列表,由另一个线程填充
有一个线程生成随机整数,并将它们放入列表中。还有两个线程同时使用列表中的项。这些线程需要汇总它们从列表中获取的项目。暂停这些线程,直到列表被填满。然后打印出两个线程的汇总结果 我认为这里应该使用Java 并发求和列表,由另一个线程填充,java,multithreading,concurrency,Java,Multithreading,Concurrency,有一个线程生成随机整数,并将它们放入列表中。还有两个线程同时使用列表中的项。这些线程需要汇总它们从列表中获取的项目。暂停这些线程,直到列表被填满。然后打印出两个线程的汇总结果 我认为这里应该使用wait()和notify()。然而,我不确定我是否正确理解这是如何工作的 此线程从列表中获取项目 @Override public void run() { try { while (list.size() > 0) { synchronized (list) {
wait()
和notify()
。然而,我不确定我是否正确理解这是如何工作的
此线程从列表中获取项目
@Override
public void run() {
try
{
while (list.size() > 0) {
synchronized (list) {
list.wait();
result += (Integer) list.remove(0);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
这就是清单上的内容
@Override
public void run() {
try {
synchronized (list) {
list.wait();
for (int i = 0; i < 10; i++) {
list.add(random.nextInt());
System.out.println("fill");
}
list.notify();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void run() {
synchronized(list) {
for (int i = 0; i < 10; i++) {
list.add(random.nextInt());
}
list.notify();
}
}
@覆盖
公开募捐{
试一试{
已同步(列表){
list.wait();
对于(int i=0;i<10;i++){
list.add(random.nextInt());
系统输出打印项次(“填写”);
}
list.notify();
}
}捕捉(中断异常e){
e、 printStackTrace();
}
}
但是,它们永远不会结束。填充线程中的notify()调用只通知一个等待的线程。只有一个线程继续提取一个整数。然后它再次等待。没有任何东西触发通知,它将永远等待。只有当列表中没有任何内容时才需要等待
@Override
public void run() {
try {
synchronized (list) {
list.wait();
for (int i = 0; i < 10; i++) {
list.add(random.nextInt());
System.out.println("fill");
}
list.notify();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void run() {
synchronized(list) {
for (int i = 0; i < 10; i++) {
list.add(random.nextInt());
}
list.notify();
}
}
与其重新发明轮子,不如使用如下阻塞队列:
public Runnable createSum( final BlockingQueue<Integer> queue, final BlockingQueue<Integer> output ) {
return new Runnable() {
public void run() {
Integer result = 0;
while( !queue.isEmpty() ) {
result += queue.take();
}
output.put( result );
}
}
}
public void go() {
BlockingQueue<Integer> input = new ArrayBlockingQueue<Integer>();
BlockingQueue<Integer> output = new ArrayBlockingQueue<Integer>();
Thread runner1 = new Thread( createSum( input, output ) );
Thread runner2 = new Thread( createSum( input, output ) );
for( int i = 0; i < 10; i++ ) {
input.put( random.nextInt() );
}
runner1.start();
runner2.start();
runner1.join();
runner2.join();
Integer result = 0;
while( !output.isEmpty() ) {
result += output.take();
}
System.out.println( result );
}
public Runnable createSum(最终阻塞队列,最终阻塞队列输出){
返回新的Runnable(){
公开募捐{
整数结果=0;
而(!queue.isEmpty()){
结果+=队列。take();
}
输出。输出(结果);
}
}
}
公开作废go(){
BlockingQueue输入=新建ArrayBlockingQueue();
BlockingQueue输出=新建ArrayBlockingQueue();
线程runner1=新线程(createSum(输入、输出));
线程runner2=新线程(createSum(输入、输出));
对于(int i=0;i<10;i++){
input.put(random.nextInt());
}
runner1.start();
runner2.start();
runner1.join();
runner2.join();
整数结果=0;
而(!output.isEmpty()){
结果+=输出。take();
}
系统输出打印项次(结果);
}
此解决方案仅在队列填满后才开始求和,但在您的解决方案中,它做的是相同的事情。您的代码有许多问题:
- 您声称有两个从列表中读取的线程,但只显示一个
- 在第一个代码块中锁定列表之前,您正在访问该列表。您需要在while循环中放置synchronized(list)语句
- 填充列表的代码等待,但没有任何通知
- 如果首先运行列表线程中的抓取项目,则列表将为空,因此不会执行任何操作。那可能不是你想要的
这里有足够的混乱证据,我建议在开始编写代码之前,试着用一种更抽象的方式来思考这个问题。我想我也误解了这个问题。这是正确的解决方案 这就填满了清单
@Override
public void run() {
try {
synchronized (list) {
list.wait();
for (int i = 0; i < 10; i++) {
list.add(random.nextInt());
System.out.println("fill");
}
list.notify();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public void run() {
synchronized(list) {
for (int i = 0; i < 10; i++) {
list.add(random.nextInt());
}
list.notify();
}
}
基本上,他们只需要锁定列表本身
这将打印出最终解决方案:
try {
sum1.join();
sum2.join();
System.out.println(sum1.getResult() + sum2.getResult());
} catch (InterruptedException e) {
e.printStackTrace();
}
无论如何,我不认为这样实现的并发没有任何实际用途——这只是一个课程任务。对不起,问题不清楚。请提供一个例子,说明应该做什么happen@gerrytan这实际上是一个(非常令人困惑的)课程任务。我想我一开始也误解了。请看我的答案。您只需通知()一次,就可以在每个整数上等待()。这几乎肯定会在第一个整数之后阻塞,但如果在线程启动之前触发notify(),则可能从一开始就阻塞。如果不允许使用更高级别的并发库,则这是您唯一的选择。或者,如果您正在构建更高级别的并发数据结构和算法,那么您必须使用这些原语来实现。所以它们肯定有实际用途。是的,我不允许使用高级库。我明白为什么它是实用的,就像你说的那样。但这取决于算法和数据结构。我的意思是,如果我正确理解并发性,那么在本例中,线程管理的成本要比使用列表的实际操作高得多。当然,如果实际操作慢一点,我想会更好。顺便说一句,你的回答很有启发性!