2014-12-06 130 views
0

我有200名學生等待進入有200個座位(25行8列)的房間。門的容量是4人。當一個學生進入房間時,他選擇隨機座位(行和列)。如果選擇的座位在第9行或更少,則需要1秒鐘的時間,18日或更短的時間需要2秒,而如果它從18日到25日需要3秒。 當他們中的任何一個人坐下時,另一個人必須進入房間。 的問題是,當第4人進入房間,他們通過一個取坐位一個,而不是一次。我該如何解決這個問題? 例如,如果2人選擇在第5排座位,他們都需要坐1秒,兩個新的學生必須進入房間。同步多線程JAVA

public class Student 
{ 
int row; 
int column; 
volatile static int mutex; 

//Generating random numbers for row and column 
public Student(Seats[][] seats) 
{ 

    this.row = (int) Math.ceil(Math.random() * 25); 
    this.column = (int) Math.ceil(Math.random() * 8); 

    if (!seats[row][column].isTaken) 
    { 
     seats[row][column].isTaken = true; 
    } else 
    { 
     do 
     { 
      this.row = (int) Math.ceil(Math.random() * 25); 
      this.column = (int) Math.ceil(Math.random() * 8); 
     } while (!seats[row][column].isTaken); 
     seats[row][column].isTaken = true; 
    } 
} 

/*Check if the mutex is 4 (4 people are in the room) then wait 
if someone enter the room increment mutex*/ 
synchronized void add() throws InterruptedException 
{ 
    while (mutex > 4) 
     wait(); 
    Student.mutex++; 

    notifyAll(); 
} 

/* Check if mutex is 0 (no one is in the room) then wait 
if the student has sit - decrement mutex and notify*/ 
synchronized void takeSeat() throws InterruptedException 
{ 
    while (mutex == 0) 
     wait(); 
    Student.mutex--; 
    notifyAll(); 

} 
} 

class Seats 
{ 
int seat; 
boolean isTaken; 

public Seats(int seat) 
{ 
    this.seat = seat; 
    this.isTaken = false; 
} 
} 


class StudentThread extends Thread 
{ 

Seats[][] seats = new Seats[25][8]; 

StudentThread(Seats[][] seats) 
{ 
    this.seats = seats; 
} 

public void run() 
{ 

    try 
    { 
     Student student = new Student(seats); 
     synchronized (seats) 
     { 
      System.out.println("Student enter the room"); 

      /*call the synchronized method from student 
      that increment the mutex*/ 
      student.add(); 

      if (Student.mutex == 4) 
      { 
       if (student.row <= 9) 
       { 
        sleep(1000); 

        student.takeSeat(); 

        System.out.println("Student take a seat at " 
          + student.row + " " + student.column); 
       } 
       if (student.row <= 18 && student.row > 9) 
       { 
        sleep(2000); 

        student.takeSeat(); 

        System.out.println("Student take a seat at " 
          + student.row + " " + student.column); 
       } 
       if (student.row <= 25 && student.row > 18) 
       { 
        sleep(3000); 

        student.takeSeat(); 

        System.out.println("Student take a seat at " 
          + student.row + " " + student.column); 
       } 
      } 
     } 
    } catch (InterruptedException e) 
    { 
     e.printStackTrace(); 
    } 
} 
} 

class Main 
{ 

public static void main(String[] args) 
{ 

    Seats[][] seats = new Seats[25][8]; 

    //Initializing the seats 
    for (int i = 0; i < 25; i++) 
     for (int j = 0; j < 8; j++) 
     { 
      seats[i][j] = new Seats(i); 
     } 

    for (int i = 0; i < 200; i++) 
    { 
     StudentThread T1 = new StudentThread(seats); 
     T1.start(); 
    } 
} 
} 
+0

你的問題是一個固定的大小?對於線程和進程見[oracle的文檔(https://docs.oracle.com/javase/tutorial/essential/concurrency/index.html) – 2014-12-06 09:44:22

+0

的代碼上''中你seat'同步部StudentThread.run'太很長時間以來,你應該重新考慮那一部分。 – didierc 2014-12-06 09:55:11

+0

你是什麼意思太長? – user3476022 2014-12-06 09:58:59

回答

2

使用Semaphore,它們對於這些類型的東西非常實用。

爲了讓這個例子更現實一點:想象一下,你需要做200 HTTP GET-請求,但服務器將禁止你,如果你運行在同一時間超過4個請求。下面的示例顯示瞭如何使用Semaphore來限制同時運行的請求數。

import java.util.Random; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.Semaphore; 

public class ResourceUsageLimiter { 

    static ExecutorService executor = Executors.newCachedThreadPool(); 
    static int requests = 20; 
    static int maxRequestsConcurrent = 4; 
    static int maxRequestTime = 1000; 
    static Random randomizer = new Random(); 
    static Semaphore openSlots = new Semaphore(maxRequestsConcurrent); 
    static long startTime = System.currentTimeMillis(); 

    public static void main(String[] args) { 

     try { 
      for (int i = 0; i < requests; i++) { 
       openSlots.acquire(); 
       executor.execute(new RequestRunner(i)); 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } finally { 
      executor.shutdown(); 
     } 
    } 

    static long time() { 
     return System.currentTimeMillis() - startTime; 
    } 

    static class RequestRunner implements Runnable { 

     int sleepTime, reqId; 

     public RequestRunner(int reqId) { 
      this.reqId = reqId; 
      sleepTime = randomizer.nextInt(maxRequestTime); 
     } 

     @Override 
     public void run() { 

      try { 
       System.out.println(time() + " " + reqId + " sleeping " + sleepTime); 
       Thread.sleep(sleepTime); 
       System.out.println(time() + " " + reqId + " sleep done"); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } finally { 
       openSlots.release(); 
      } 
     } 

    } 

} 

Ofcourse,另一種方式限制在例如同時運行的請求的最大數量是使用一個線程池的4

+0

有沒有辦法在不使用Executor的情況下運行固定數量的線程? – user3476022 2014-12-06 17:08:29

+0

@ user3476022我不確定我是否理解這個問題。你總是可以做'新線程(Runnable).start()'? – vanOekel 2014-12-06 17:13:44

+0

當我有200個線程,例如,是否有可能只有4人能夠同時運行,其中一些4個線程結束時,從196左新開始運行? 是否可以在不使用Executor類的情況下完成? – user3476022 2014-12-06 17:17:07