多线程 Java 应用程序中的问题 - 同步方法未按预期工作

发布于 2024-12-06 03:26:24 字数 4661 浏览 0 评论 0原文

我正在编写一个类似于java中的生产者-消费者的程序(但只有消费者部分,没有生产者线程)。尽管我正在调用同步方法的代码,但看起来关键区域正在由多个线程同时执行。

下面是代码:

Class Main.java:

package principal;

public class Main {

/**
 * @param args
 */
public static void main(String[] args) {
    final int tamanho_buffer=10;
    final int quantidade_threads=10;

    Pedido buffer[] = new Pedido[tamanho_buffer];
    Consumidor consumidor[] = new Consumidor[quantidade_threads];

    for (int i=0;i<tamanho_buffer;i++) {
        buffer[i]=new Pedido();
    }

    for (int i=0;i<quantidade_threads;i++) {
        consumidor[i]=new Consumidor();
    }

    for (int i=0;i<tamanho_buffer;i++) {
        int identificador[]=new int[Pedido.getTamanho_identificador()];
        identificador[0]=i;
        buffer[i].setIdentificador(identificador);
        buffer[i].setTexto("pacote de dados");
    }

    Consumidor.setBuffer(buffer);
    Consumidor.setTamanho_buffer(tamanho_buffer);

    for (int i=0;i<quantidade_threads;i++) {
        consumidor[i].start();
    }

    for (int i=0;i<quantidade_threads;i++) {
        try {
            consumidor[i].join();
        }catch(InterruptedException e ){
            System.out.println("InterruptedException lancada");
        }
    }

    System.out.println("Processamento encerrado.");

}

}

Class Pedido.java:

package principal;

    public class Pedido {
private int identificador[];
private String texto;
static int tamanho_identificador=10;
int ti=tamanho_identificador;

public Pedido() {
    this.identificador= new int[this.ti];
}

public static int getTamanho_identificador() {
    return tamanho_identificador;
}

public int[] getIdentificador() {
    return identificador;
}
public void setIdentificador(int[] identificador) {
    this.identificador = identificador;
}
public String getTexto() {
    return texto;
}
public void setTexto(String texto) {
    this.texto = texto;
}

}

Class Consumidor.java

package principal;

import java.util.Date;
import java.text.DateFormat;
import java.text.SimpleDateFormat;

public class Consumidor extends Thread {

private static Pedido buffer[];
private static int tamanho_buffer;
private static int posicao=0;

public static void setTamanho_buffer(int tamanhoBuffer) {
    tamanho_buffer = tamanhoBuffer;
}

public static void setBuffer(Pedido[] buffer) {
    Consumidor.buffer = buffer;
}

public void run() {
    DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
    while (posicao < Consumidor.tamanho_buffer ) {
   //           int identificador;
   //           identificador=buffer[posicao].getIdentificador()[0];;

        Date datainicio = new Date();
        String inicio=dateFormat.format(datainicio);

        try {
            Consumidor.sleep(1000);
        } catch(InterruptedException e) {
            System.out.println("InterruptedException lancada");
        }

        Date datafim = new Date();
        String fim=dateFormat.format(datafim);

        consomebuffer(inicio,fim);

    }
}

synchronized void consomebuffer(String inicio, String fim) {
    if (posicao < Consumidor.tamanho_buffer ) {
        int identificador;
        identificador=buffer[posicao].getIdentificador()[0];
        System.out.println("Thread: "+Thread.currentThread()+" Pedido: "+identificador+" Inicio: "+inicio+" Fim: "+fim+" posicao "+posicao);
        posicao++;
    }
}
}

方法 consomebuffer 是同步的,但看起来变量 posicao(位置的葡萄牙语名称)正在被其他线程同时访问,即不应该发生,因为它是一个同步方法。程序输出如下:

Thread: Thread[Thread-7,5,main] Pedido: 0 Inicio: 2011/09/24 21:14:18 Fim: 2011/09/24 21:14:19 posicao 0

Thread : 线程[Thread-6,5,main] pedido: 0 起始: 2011/09/24 21:14:18 Fim: 2011/09/24 21:14:19 posicao 0

线程: Thread[Thread-2,5,main] Pedido: 0 Inicio: 2011/09/24 21:14:18 Fim: 2011/ 09/24 21:14:19 波西考 0

主题:线程[Thread-9,5,main] Pedido: 0 起始: 2011/09/24 21:14:18 Fim: 2011/09/24 21:14:19 posicao 0

线程: 线程[Thread-3,5,main ] 佩迪多:4 起始:2011/09/24 21:14:18 菲姆: 2011/09/24 21:14:19 posicao 4

Thread: Thread[Thread-5,5,main] Pedido: 5 Inicio: 2011/09/24 21:14:18 Fim: 2011/09/24 21:14: 19 posicao 5

线程: 线程[线程-0,5,main] Pedido: 0 起始: 2011/09/24 21:14:18 起始: 2011/09/24 21:14:19 posicao 5

主题: Thread[Thread-8,5,main] Pedido: 0 起始: 2011/09/24 21 :14:18 发布时间: 2011/09/24 21:14:19 posicao 5

主题: 主题[Thread-4,5,main] Pedido: 5 起始: 2011/09/24 21:14:18 Fim: 2011/09/24 21:14:19 posicao 5

主题:线程[Thread-1,5,main] Pedido: 0 起始: 2011/09/24 21:14:18 Fim: 2011/09/24 21:14:19 posicao 0

处理过程。

意识到位置值在不同线程之间重复出现。在输出中,posicao 在调用同步方法的每个线程中应该有不同的值。

I am coding a program similar to producer-consumer in java (but with the consumer only portion, with no producer thread). It looks like the critical region is being executed at the same time by multiple threads despite the fact that I am calling the code of a synchronized method.

Here is the code:

Class Main.java:

package principal;

public class Main {

/**
 * @param args
 */
public static void main(String[] args) {
    final int tamanho_buffer=10;
    final int quantidade_threads=10;

    Pedido buffer[] = new Pedido[tamanho_buffer];
    Consumidor consumidor[] = new Consumidor[quantidade_threads];

    for (int i=0;i<tamanho_buffer;i++) {
        buffer[i]=new Pedido();
    }

    for (int i=0;i<quantidade_threads;i++) {
        consumidor[i]=new Consumidor();
    }

    for (int i=0;i<tamanho_buffer;i++) {
        int identificador[]=new int[Pedido.getTamanho_identificador()];
        identificador[0]=i;
        buffer[i].setIdentificador(identificador);
        buffer[i].setTexto("pacote de dados");
    }

    Consumidor.setBuffer(buffer);
    Consumidor.setTamanho_buffer(tamanho_buffer);

    for (int i=0;i<quantidade_threads;i++) {
        consumidor[i].start();
    }

    for (int i=0;i<quantidade_threads;i++) {
        try {
            consumidor[i].join();
        }catch(InterruptedException e ){
            System.out.println("InterruptedException lancada");
        }
    }

    System.out.println("Processamento encerrado.");

}

}

Class Pedido.java:

package principal;

    public class Pedido {
private int identificador[];
private String texto;
static int tamanho_identificador=10;
int ti=tamanho_identificador;

public Pedido() {
    this.identificador= new int[this.ti];
}

public static int getTamanho_identificador() {
    return tamanho_identificador;
}

public int[] getIdentificador() {
    return identificador;
}
public void setIdentificador(int[] identificador) {
    this.identificador = identificador;
}
public String getTexto() {
    return texto;
}
public void setTexto(String texto) {
    this.texto = texto;
}

}

Class Consumidor.java

package principal;

import java.util.Date;
import java.text.DateFormat;
import java.text.SimpleDateFormat;

public class Consumidor extends Thread {

private static Pedido buffer[];
private static int tamanho_buffer;
private static int posicao=0;

public static void setTamanho_buffer(int tamanhoBuffer) {
    tamanho_buffer = tamanhoBuffer;
}

public static void setBuffer(Pedido[] buffer) {
    Consumidor.buffer = buffer;
}

public void run() {
    DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
    while (posicao < Consumidor.tamanho_buffer ) {
   //           int identificador;
   //           identificador=buffer[posicao].getIdentificador()[0];;

        Date datainicio = new Date();
        String inicio=dateFormat.format(datainicio);

        try {
            Consumidor.sleep(1000);
        } catch(InterruptedException e) {
            System.out.println("InterruptedException lancada");
        }

        Date datafim = new Date();
        String fim=dateFormat.format(datafim);

        consomebuffer(inicio,fim);

    }
}

synchronized void consomebuffer(String inicio, String fim) {
    if (posicao < Consumidor.tamanho_buffer ) {
        int identificador;
        identificador=buffer[posicao].getIdentificador()[0];
        System.out.println("Thread: "+Thread.currentThread()+" Pedido: "+identificador+" Inicio: "+inicio+" Fim: "+fim+" posicao "+posicao);
        posicao++;
    }
}
}

The method consomebuffer is synchronized but it looks like the variable posicao (portuguese name for position) is being accessed by the other threads at the same time, that should not happen, coz it is a synchronized method. The program output is something like this:

Thread: Thread[Thread-7,5,main] Pedido: 0 Inicio: 2011/09/24 21:14:18 Fim: 2011/09/24 21:14:19 posicao 0

Thread: Thread[Thread-6,5,main] Pedido: 0 Inicio: 2011/09/24 21:14:18 Fim: 2011/09/24 21:14:19 posicao 0

Thread: Thread[Thread-2,5,main] Pedido: 0 Inicio: 2011/09/24 21:14:18 Fim: 2011/09/24 21:14:19 posicao 0

Thread: Thread[Thread-9,5,main] Pedido: 0 Inicio: 2011/09/24 21:14:18 Fim: 2011/09/24 21:14:19 posicao 0

Thread: Thread[Thread-3,5,main] Pedido: 4 Inicio: 2011/09/24 21:14:18 Fim: 2011/09/24 21:14:19 posicao 4

Thread: Thread[Thread-5,5,main] Pedido: 5 Inicio: 2011/09/24 21:14:18 Fim: 2011/09/24 21:14:19 posicao 5

Thread: Thread[Thread-0,5,main] Pedido: 0 Inicio: 2011/09/24 21:14:18 Fim: 2011/09/24 21:14:19 posicao 5

Thread: Thread[Thread-8,5,main] Pedido: 0 Inicio: 2011/09/24 21:14:18 Fim: 2011/09/24 21:14:19 posicao 5

Thread: Thread[Thread-4,5,main] Pedido: 5 Inicio: 2011/09/24 21:14:18 Fim: 2011/09/24 21:14:19 posicao 5

Thread: Thread[Thread-1,5,main] Pedido: 0 Inicio: 2011/09/24 21:14:18 Fim: 2011/09/24 21:14:19 posicao 0

Processamento encerrado.

Realize that the position value is appearing repeated between different threads. In the output posicao should have a different value in each thread that calls the synchronized method.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

_蜘蛛 2024-12-13 03:26:24

每个 Thread 实例都在自身同步。为了使所有线程互斥,它们必须在一个公共对象上同步。

也就是说,

public synchronized method(int parameter)
{
    //do some stuff
}

public method(int parameter)
{
    synchronized (this)
    {
        //do some stuff
    }
}

如果您希望一堆线程彼此同步,则需要为它们提供一个可以同步的公共对象。

例如,您可以在 Consumidor.java 的构造函数中添加

public Consumidator(Object monitor)
{
     myMonitor = monitor
}

,然后在 run have 中

void consomebuffer(String inicio, String fim) {
  synchronized (myMonitor)
  {
    if (posicao < Consumidor.tamanho_buffer ) {
        int identificador;
        identificador=buffer[posicao].getIdentificador()[0];
        System.out.println("Thread: "+Thread.currentThread()+" Pedido: "+identificador+" Inicio: "+inicio+" Fim: "+fim+" posicao "+posicao);
        posicao++;
    }
  }
}

添加。然后,当您创建 Consumidadors 数组时,向它们传递一个共享对象以进行同步。

Each Thread instance is synchronising on itself. To make all of the threads mutually exclusive, they have to synchronise on a common object.

That is,

public synchronized method(int parameter)
{
    //do some stuff
}

is shorthand for

public method(int parameter)
{
    synchronized (this)
    {
        //do some stuff
    }
}

If you want a bunch of Threads to synchronise with each other, you need to make available to them a common object to synchronize on.

For example, you could add in the constructor of Consumidor.java

public Consumidator(Object monitor)
{
     myMonitor = monitor
}

then in run have

void consomebuffer(String inicio, String fim) {
  synchronized (myMonitor)
  {
    if (posicao < Consumidor.tamanho_buffer ) {
        int identificador;
        identificador=buffer[posicao].getIdentificador()[0];
        System.out.println("Thread: "+Thread.currentThread()+" Pedido: "+identificador+" Inicio: "+inicio+" Fim: "+fim+" posicao "+posicao);
        posicao++;
    }
  }
}

Then when you create your array of Consumidadors, pass them a shared object to synchronize on.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文