Java多线程程序

标签 java multithreading concurrency

我的任务是创建一个程序,该程序具有:

  • 客户端
  • 博物馆

Client 使用Gate 类进入和离开Museum。博物馆一次最多可接待 5 位客户。

当我在某个时候输入 1000 个 Clients 时,输出会给我不需要的数字。

示例输出:


Client (358) is leaving the Museum!   number of customers: 2
Client (214) is entering the Museum!   number of customers: 3
Client (214) is leaving the Museum!   number of customers: 2
Client (73) is entering the Museum!   number of customers: 5
Client (73) is leaving the Museum!   number of customers: 5
Client (397) is entering the Museum!   number of customers: 5
Client (76) is entering the Museum!   number of customers: 6
----------------------------------------------------------------
Client (930) is entering the Museum!   number of customers: 7
Client (930) is leaving the Museum!   number of customers: 6
Client (308) is entering the Museum!   number of customers: 6
Client (183) is entering the Museum!   number of customers: 6
Client (183) is leaving the Museum!   number of customers: 5
----------------------------------------------------------------
Client (647) is entering the Museum!   number of customers: 7
Client (647) is leaving the Museum!   number of customers: 6
----------------------------------------------------------------
Client (540) is entering the Museum!   number of customers: 7

我预计客户将尝试在某个随机时间进入,当博物馆中有 5 个或更多客户时,他们将不得不等待其他线程结束其任务。

这是我的代码:


客户端.java

package client;

import gate.Gate;
import museum.Museum;

import java.util.Random;

public class Client extends Thread {
    private static int id = 0;
    private int clientID;

    public Client() {
        Client.id++;
        this.clientID = id;
    }

    @Override
    public void run() {
        this.enterMuseum();
        this.leaveMuseum();
    }

    ///////////////////////////////////////////////////////////////////////////////////

    private void enterMuseum() {
        try {
            Thread.sleep(new Random().nextInt(401) + 100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }


        while (true) {
            if (Gate.atomCustomer.get() < 5) {
                Museum.getGate(0).enter(this);
                break;
            }
        }
    }

    private void leaveMuseum() {
        Museum.getGate(1).exit(this);
    }

    public int getClientId() {
        return this.clientID;
    }

    ////////////////////////////////////////////////////////////////////////////////////
}

门.java

package gate;

import client.Client;

import java.util.concurrent.atomic.AtomicInteger;

public class Gate {
    public static AtomicInteger atomCustomer = new AtomicInteger();

    public Gate() {
    }

    public void enter(Client client) {
        if (atomCustomer.get() > 5) {
            System.out.println("----------------------------------------------------------------");
        }
        atomCustomer.incrementAndGet();

        System.out.println("Client (" + client.getClientId() + ") is entering the Museum!" +
                "   number of customers: " + atomCustomer.get());
    }

    public void exit(Client client) {
        atomCustomer.decrementAndGet();
        System.out.println("Client (" + client.getClientId() + ") is leaving the Museum!" +
                "   number of customers: " + atomCustomer.get());
    }
}

博物馆.java

package museum;

import gate.Gate;

public class Museum {
    private static Gate[] gate = new Gate[2];

    public Museum() {
        gate[0] = new Gate();
        gate[1] = new Gate();
    }

    public static Gate getGate(final int numberOfGate) {
        return Museum.gate[numberOfGate];
    }
}

应用程序测试.java

import client.Client;
import museum.Museum;

import java.util.ArrayList;
import java.util.Scanner;

public class ApplicationTest implements Runnable {
    private static int NUMBER_OF_CLIENTS = 0;
    private static ArrayList<Client> listOfClients;
    private static Scanner sc = new Scanner(System.in);

    public static void main(String[] args) {
        new Thread(new ApplicationTest()).start();
    }


    private static void init() {
        while (NUMBER_OF_CLIENTS < 5) {
            System.out.println("How many clients?( > 5): ");
            NUMBER_OF_CLIENTS = sc.nextInt();
        }

        listOfClients = new ArrayList<>(NUMBER_OF_CLIENTS);
        new Museum();

        for (int i = 0; i < NUMBER_OF_CLIENTS; i++) {
            ApplicationTest.listOfClients.add(new Client());
        }
        for (Client c : listOfClients) {
            c.start();
        }
    }


    @Override
    public void run() {
        ApplicationTest.init();
    }
}

如有任何帮助,我将不胜感激。谢谢你的时间。问。

最佳答案

一些建议,不要使用公共(public)静态变量和静态方法,如 museum.getGate() 或原子客户计数器(这样更难理解谁使用了什么)。此外,Client 类应该与“计数器”逻辑完全隔离;也就是说,客户端应该简单地调用 gate.enter(),访问检查应该在 Gate 或 Museum 中完成。

然后是“关键”部分,您尝试在

中为客户端分配“许可”
 while (true) {
   if (Gate.atomCustomer.get() < 5) {
     //use museum.tryEnter() instead..
     Museum.getGate(0).enter(this);
     break;
   }
 }

这里,如果两个线程同时调用get(),它们都会发现客户的数量是eg。 4、都会进入(并发问题)。

确保只有一个客户端获得许可的一种方法是向某些同步方法添加嵌套调用,例如

private synchronized boolean tryEnter() {
    if (counter<5) {
        counter++;
        return true;
    }
    else {
        return false;
    }
}

但是分配许可的更好方法是使用信号量(这样您甚至不需要那个繁忙的循环)。 https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.html

关于Java多线程程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54855962/

相关文章:

java - 如何在 Wildfly 11 上的异步事件中保留 CDI 上下文?

java - Tomcat 不会停止。我该如何调试呢?

c# - 线程池 - 如何从工作线程调用主线程中的方法(带参数)

ios - 使用核心数据时卡住 UI .mainQueueConcurrencyType

golang并发同步问题

java - 是什么导致 "NoSuchMethodError: org.springframework.beans.BeanWrapper.setAutoGrowCollectionLimit(I)V?"

java - Java中的二维数组按行排序

java - 我如何处理 Selenium 和 Java 中的引导日期选择器

python - 奇怪的线程行为

java - 为什么并行流不使用ForkJoinPool的所有线程? [复制]