1

私はJavaでプロデューサー-コンシューマーに似たプログラムをコーディングしています(ただし、コンシューマーのみの部分で、プロデューサースレッドはありません)。同期メソッドのコードを呼び出しているにもかかわらず、クリティカル領域が複数のスレッドによって同時に実行されているようです。

コードは次のとおりです。

クラス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.");

}

}

クラス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;
}

}

クラス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(位置のポルトガル語名)が他のスレッドによって同時にアクセスされているように見えます。これは発生しないはずです。同期されたメソッドです。プログラムの出力は次のようになります。

スレッド:スレッド[スレッド-7,5、メイン]ペディド:0イニシオ:2011/09/24 21:14:18フィム:2011/09/24 21:14:19 posicao 0

スレッド:スレッド[スレッド-6,5、メイン]ペディド:0イニシオ:2011/09/24 21:14:18フィム:2011/09/24 21:14:19 posicao 0

スレッド:スレッド[スレッド-2,5、メイン]ペディド:0イニシオ:2011/09/24 21:14:18フィム:2011/09/24 21:14:19 posicao 0

スレッド:スレッド[スレッド-9,5、メイン]ペディド:0イニシオ:2011/09/24 21:14:18フィム:2011/09/24 21:14:19 posicao 0

スレッド:スレッド[スレッド-3,5、メイン]ペディド:4イニシオ:2011/09/24 21:14:18フィム:2011/09/24 21:14:19 posicao 4

スレッド:スレッド[スレッド-5,5、メイン]ペディド:5イニシオ:2011/09/24 21:14:18フィム:2011/09/24 21:14:19 posicao 5

スレッド:スレッド[スレッド-0,5、メイン]ペディド:0イニシオ:2011/09/24 21:14:18フィム:2011/09/24 21:14:19 posicao 5

スレッド:スレッド[スレッド-8,5、メイン]ペディド:0イニシオ:2011/09/24 21:14:18フィム:2011/09/24 21:14:19 posicao 5

スレッド:スレッド[スレッド-4,5、メイン]ペディド:5イニシオ:2011/09/24 21:14:18フィム:2011/09/24 21:14:19 posicao 5

スレッド:スレッド[スレッド-1,5、メイン]ペディド:0イニシオ:2011/09/24 21:14:18フィム:2011/09/24 21:14:19 posicao 0

Processamentoencerrado。

位置の値が異なるスレッド間で繰り返されていることを認識してください。出力では、posicaoは、同期されたメソッドを呼び出すスレッドごとに異なる値を持つ必要があります。

4

1 に答える 1

2

各スレッドインスタンスはそれ自体で同期しています。すべてのスレッドを相互に排他的にするには、共通のオブジェクトで同期する必要があります。

あれは、

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
}

その後、実行中に持っています

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++;
    }
  }
}

次に、Consumidadorの配列を作成するときに、同期する共有オブジェクトをそれらに渡します。

于 2011-09-25T00:57:39.587 に答える