solução livre de fome do clássico problema Via Única Ponte Problem

WebStormer:

Eu estou tentando fornecer uma solução para o clássico Via Única Ponte Problema, onde uma única ponte da pista conecta duas aldeias. Ele utiliza apenas um fio e por isso pode se tornar um impasse se os agricultores saltar em ambos os lados da ponte, ao mesmo tempo. Esta é a minha solução até agora, mas eu não sei como fazê-lo sem fome?

public class SingleLaneBridge {

  public static void main(String[] args)
  {
    final Bridge bridge = new Bridge();

    Thread thNorthbound = new Thread( new Runnable() {

      @Override
      public void run() {

        while(true) {
          Farmer farmer = new Farmer(bridge);
          Thread th = new Thread(farmer);
          farmer.setName("North Farmer : "+ th.getId());
          th.start();
          try {
            TimeUnit.SECONDS.sleep((long)(Math.random()*10));
          } catch(InterruptedException iex) {
            iex.printStackTrace();
          }
        }

      }
    });

    Thread thSouthbound = new Thread( new Runnable() {

      @Override
      public void run() {

        while(true) {
          Farmer farmer = new Farmer(bridge);
          Thread th = new Thread(farmer);
          farmer.setName("South Farmer : "+th.getId());
          th.start();
          try {
            TimeUnit.SECONDS.sleep((long)(Math.random()*10));
          }
          catch(InterruptedException iex)
          {
            iex.printStackTrace();
          }
        }
      }
    });

    thNorthbound.start();
    thSouthbound.start();
  }

}

class Bridge {
  private final Semaphore semaphore;

  public Bridge() {
    semaphore = new Semaphore(1);
  }
  public void crossBridge(Farmer farmer) {
    try {
      System.out.printf("Farmer trying to cross the bridge.\n",farmer.getName());
      semaphore.acquire();
      System.out.printf("Farmer crossing the bridge.\n",farmer.getName());
      long duration = (long)(Math.random() * 10);
      TimeUnit.SECONDS.sleep(duration);
    }
    catch(InterruptedException iex) {
      iex.printStackTrace();
    }
    finally {
      System.out.printf("Farmer as crossed the bridge.\n",farmer.getName());
      semaphore.release();
    }
  }
}

class Farmer implements Runnable
{
  private String name;
  private Bridge bridge;

  public Farmer(Bridge bridge)
  {
    this.bridge = bridge;
  }

  public void run() {
    bridge.crossBridge(this);
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }
}
ruach:

Primeiro, um aviso: Peças para a sua pergunta realmente não faz sentido, mas acho que pode ser devido mais ao mau uso da terminologia do que a mal-entendidos , por si só . Infelizmente, a terminologia é realmente muito importante se você deseja comunicar a sua pergunta com clareza e fazer sentido do que você lê. Eu fiz o meu melhor abaixo, mas é bem possível que eu estou mal-entendido a sua pergunta real.


Ele utiliza apenas um segmento [...]

Eu não tenho certeza do que você quer dizer; ele realmente lança um segmento separado para cada agricultor.

É [...] podem tornar-se num impasse se os agricultores saltar em ambos os lados da ponte, ao mesmo tempo.

Isso não é correto; o mecanismo só travando aqui é um único semáforo, e qualquer segmento que adquire uma licença é garantida para liberá-lo antes de tentar novamente para adquiri-lo, por isso não há possibilidade de impasse .


Vejo três grandes problemas com seu código:

  1. Sua introdução sugere que ele está tentando modelar uma ponte single-lane; mas ele realmente não fazer isso, pelo menos como eu entendo o conceito de uma "ponte single-lane". Especificamente:
    • Seu código permite que apenas um agricultor a utilizar a ponte em determinado momento; mas se há muitos agricultores que todos querem cruzar a ponte na mesma direção, em seguida, uma "ponte single-lane" permitiria isso. (Uma "ponte single-lane" deverão prevenir dois agricultores a partir do cruzamento em opostos instruções.)
      • É este o problema que você quis dizer quando disse que sua solução "usa apenas um thread"?
    • Se os agricultores F e G são ambos indo na mesma direção, e agricultor F chega antes agricultor G , eu acho que uma "ponte single-lane" jamais teria agricultor G cruz antes agricultor F . Seu código, no entanto, não fornece essa garantia. (NB Esta garantia só se aplica aos agricultores que dirigem a mesma direção. Se os agricultores estão indo na opostas direções, pode ser válida para obter agricultor G ir primeiro se já existe outro agricultor indo na mesma direção que agricultor G . Essa é uma decisão de design para que você faça.)
  2. Seu código chama acquireem um try-bloco, e depois chama releasena correspondente finally-bloco. Isso não é seguro, porque isso significa que um fio pode liberar uma licença, mesmo que esse segmento nunca adquiriu com sucesso uma licença. (Assim, por exemplo, se fio T detém a licença e tópicos U e V são ambos de espera para adquirir a licença, em seguida, uma chamada para Thread.interrupta linha U fará com que passe U para lançar uma InterruptedExceptione linha liberação T , autorização do fio deixando, assim, V imediatamente adquirir a licença!)
  3. Em média, na quantidade de tempo que um agricultor está usando a ponte, dois novos agricultores vai aparecer, uma viagem em cada sentido. Uma vez que (como mencionado acima) só permitir que um agricultor a usar a ponte de cada vez, isso significa que você vai continuar caindo mais e mais para trás, com mais e mais agricultores esperando para usar a ponte.
    • É este o problema que você quis dizer quando disse que sua solução não é "inanição-free"?

Mas para responder a sua pergunta específica:

[...] Não estou certo de como fazê-lo sem fome?

Se você escrever new Semaphore(1, true)em vez de apenas new Semaphore(1)(ou seja, se você definir "parâmetro justiça" do semáforo a true), então o seu semáforo vai garantir que os agricultores podem utilizar a ponte na ordem em que eles chegam. Isso irá garantir que nenhum agricultor-thread vai morrer de fome, porque cada agricultor será garantido para adquirir a licença, logo que o agricultor anterior lançou-lo.

. . . mas mesmo com esse parâmetro justiça no lugar, você ainda tem o problema (mencionado acima) que os agricultores continuam aparecendo mais rápido do que você pode obter através deles. Isso pode fazer parecer que você tem uma fome de recursos problema, mas realmente o problema é só que você não tem o suficiente do recurso para saber como você está tentando usá-lo.

Para corrigir isso, você realmente precisa questão correção # 1 acima, e permitir que vários agricultores para atravessar a ponte, ao mesmo tempo, enquanto eles estão viajando na mesma direção. Eu não acho que um semáforo de contagem como java.util.concurrent.Semaphoreestá indo cortá-lo; essa classe é útil se você precisa para garantir que, no máximo n licenças são adquiridas em um determinado momento, mas no seu caso não há nenhuma restrição sobre o número de licenças que podem ser adquiridos, desde que todos os titulares estão viajando na mesma direção.

Em vez disso, eu acho que você vai querer algo como o seguinte:

  • Um AtomicIntegerou similar para saber quantos agricultores atualmente tem permissão para atravessar.
  • Um threadsafe Listdos agricultores à espera de norte curso, e um dos agricultores que esperam para o sul viagem.
  • Farmer tem um sinalizador booleano para indicar se ele tem permissão para usar a ponte.
  • Quando os agricultores mostram-se, se a ponte já está em uso, acrescentam-se à lista apropriada, digite um synchronized/ waitloop até a sua bandeira está definido para true.
  • Quando os agricultores terminar de usar a ponte, eles atualizar o AtomicInteger, e se agora é zero, eles verificar quaisquer agricultores de espera e acordá-los.

Acho que você gosta

Origin http://43.154.161.224:23101/article/api/json?id=362941&siteId=1
Recomendado
Clasificación