使用信号量在 Java 中用餐哲学家

Posted

技术标签:

【中文标题】使用信号量在 Java 中用餐哲学家【英文标题】:Dining philosophers in java using semaphores 【发布时间】:2017-04-04 22:36:39 【问题描述】:

我想使用 java 信号量来解决哲学家就餐问题,但我被卡住了。最高 id 的筷子应该是可用的,但它似乎总是被拿走,我不知道为什么。谁能告诉我哪里出错了?

分叉类:

class Fork 
public static Semaphore fork = new Semaphore(1);
public int id;

Fork(int id) 
    this.id = id;


public int getId() 
    return id;


public boolean take() 
    return fork.tryAcquire();


public void putDown() 
    fork.release();

哲学家班:

class Philosopher extends Thread 

private Fork fork_low;
private Fork fork_high;
private String name;

Philosopher(Fork fork_low, Fork fork_high, String name) 
    this.fork_low = fork_low;
    this.fork_high = fork_high;
    this.name = name;


public void run() 

    try 
        sleep(1000);
     catch (InterruptedException ex) 
    

    while (true) 
        eat();
    


private void eat()
    if(fork_low.take())
        if(fork_high.take())
            try 
                sleep(2000); // eating;
             catch (InterruptedException ex)  

            fork_high.putDown();
            fork_low.putDown();  

        
        else
            fork_low.putDown();
        
    

主要:

public static void main(String[] args) 
    String[] names = "Plato", "Aristotle", "Cicero", "Confucius", "Eratosthenes";
    Fork[] fork = new Fork[5];
    Philosopher[] philosopher = new Philosopher[5];

    for (int i = 0; i < fork.length; i++) 
        fork[i] = new Fork(i);
    

    for (int i = 0; i < philosopher.length; i++) 

        if (i != philosopher.length - 1) 
            philosopher[i] = new Philosopher(fork[i], fork[i+1], names[i]);
            philosopher[i].start();
         else 
            philosopher[i] = new Philosopher(fork[0], fork[i], names[i]);
            philosopher[i].start();
        
    

【问题讨论】:

【参考方案1】:

你有一个死锁,因为 Semaphore 在 Fork 类中是静态的,相当于只有一个 fork 可用。当您使信号量不是静态的(同时运行 2 个随机哲学家)时,它会完美运行。

您可以在 JDK 的内置工具 jvisualvm 中观察您的线程。

【讨论】:

【参考方案2】:

这是用 C 语言解决的同一个问题,有解释

#include <stdio.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>  
//if not used then gives warning for sleep used

//semaphore are basically designed to share the resources
// here the sem_t is the data type for the semaphore
sem_t room;//counting semaphore bcoz here only one instance of room butchair has 4
sem_t spoon[5]; //this is binary semaphore since every spoon has its own instance


void * philosopher(void *);
void eat(int);
int main()

int i;
int a[5];
pthread_t tid[5];// threads here are refrence to philosophers or diners bcoz we will have multiple users dining
                  
sem_init(&room,0,4);  
//1.pointer to declared semaphore
//2.pshared which has 0,1 value that is if 0 ->shared between threads                        
//                                      if 1 ->shared between process
//3.value with whch u initalise the semaphore
for(i=0;i<5;i++)
    //5 binary semaphore each for individual spoon
    sem_init(&spoon[i],0,1);


for(i=0;i<5;i++)
    a[i]=i;//allow 5 to enter at a time and deadlock occurs so let 4 of them in
    pthread_create(&tid[i],NULL,philosopher,(void*)&a[i]);
  //1.thread id 2.NULL 3.function 4.what you want to pass to the new thread   
  //here we pass the address of philosophers number to function


for(i=0;i<5;i++)
    pthread_join(tid[i],NULL);



void * philosopher(void * num)
int phil=*(int *)num; //cast the number passed as void to integer
//put sem_wait on both semaphore room and spoon
sem_wait(&room);//checks if resource is available,if then allocates and blocks semaphore
// room is counting semaphore so any is alocated then it decrements the count of total semaphore and 
// if all are allocated then it blocks thread and places it on queue untill resource is freed
printf("\nPhilospher number %d has sat on dining table\n",phil);
  
  sem_wait(&spoon[phil]);
  sem_wait(&spoon[(phil+1)%5]);
  //spoon is binary so if value of semaphore is 1 it is changed to 0 which means semaphore is allocated and cannot be used
  
  eat(phil);
  sleep(2);
  printf("\nPhilosopher %d has finished eating\n",phil);
  //free the semaphores so others in thread can use resources
  //returns +ve value on freeing semaphore
  //for binary semaphore if queue is empty then change semaphore value to 1 if not empty then remove process from queue and 
  // get it ready for allocation
  sem_post(&spoon[(phil+1)%5]);
  sem_post(&spoon[phil]);
  sem_post(&room);
   

void eat(int phil)
  printf("\nPhilosopher %d is eating now\n",phil);

【讨论】:

以上是关于使用信号量在 Java 中用餐哲学家的主要内容,如果未能解决你的问题,请参考以下文章

使用二进制信号量用餐哲学家

Java并发编程系列之Semaphore详解

在 Java 中用餐哲学家

使用信号量 (BACI) 就餐哲学家

使用信号量的餐饮哲学家(BACI)

信号量解决哲学家就餐问题(GUI动态演示)