2014-12-06 3 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 docs] (https://docs.oracle.com/javase/tutorial/essential/concurrency/index.html) –

+0

Ваш синхронизированный раздел кода на 'seat' в' StudentThread.run' тоже вы должны пересмотреть эту часть. – didierc

+0

Что значит слишком долго? – user3476022

ответ

2

Используйте Semaphore, они очень практичны для такого рода вещей.

Чтобы сделать пример более реалистичным: представьте, что вам нужно выполнить 200 запросов HTTP-запросов, но сервер запретит вам, если вы одновременно запускаете более 4 запросов. В приведенном ниже примере показано, как можно ограничить количество запросов, запущенных одновременно с помощью Семафора.

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

+0

@ user3476022 Я не уверен, что понимаю этот вопрос. Вы всегда можете создать новую тему (Runnable) .start() '? – vanOekel

+0

Например, если у меня есть 200 потоков, возможно ли, что только 4 из них будут выполняться одновременно, и когда некоторые из этих 4 потоков будут завершены, новый из 196 слева начнет работать? Можно ли сделать это без использования классов, подобных Executor? – user3476022

Смежные вопросы