【问题标题】:Problem in multi-threaded Java application - synchronized method not working as expected多线程 Java 应用程序中的问题 - 同步方法未按预期工作
【发布时间】:2011-09-25 00:47:42
【问题描述】:

我正在编写一个类似于 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(位置的葡萄牙语名称)正在被其他线程同时访问,这不应该发生,因为它是一个同步方法。程序输出是这样的:

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

加工工艺。

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

【问题讨论】:

    标签: java multithreading concurrency synchronized synchronize


    【解决方案1】:

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

    也就是说,

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

    然后,当您创建 Consumidadors 数组时,将共享对象传递给它们以进行同步。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-08-11
      • 1970-01-01
      • 2018-04-27
      • 2014-03-10
      • 1970-01-01
      相关资源
      最近更新 更多