私は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は、同期されたメソッドを呼び出すスレッドごとに異なる値を持つ必要があります。