I'm working on a queue project where the program is simulating a grocery store. In my program, I have a method call that sets up a random variable that represents the time that it takes to service the customer in queue. The total iterations are 60, signifying minutes. Say if the first customer is given a 4 minute wait time, I need to be able to decrement the time after each minute until it reaches 0. I cannot figure out how to decrement the value stored in the queue named myQueue. Any suggestions how I can decrease the value stored in the queue after each minute?
import java.util.*;
import java.util.Random;
public class GroceryStore{
public static void main (String[] args){
int newCust=0; //to hold random variable 1-4 for 25% chance of new customer
Queue<Integer> myQueue = new LinkedList<Integer>(); //instantiates new queue
int wait = 0;
int numCust = 0; //holds counter for number of customer
for (int i = 1; i <= 60; i++) //iterator to cycle through 60 minutes
{
Random randomNum = new Random();
newCust = randomNum.nextInt(4)+1; //gives random #1-4, if 1, new cust added
if(newCust == 1) //if statement to execute code if new cust added
{
Customer cust = new Customer();
wait = cust.getServiceTime(); //stores wait time in variable
myQueue.add(wait); //adds customer to the queue by wait time
System.out.println("New customer added to queue, queue length is now " + myQueue.size());
}
if(myQueue.isEmpty()) //if to check if queue is empty and skip other conditionals
System.out.println("-----------");
else if(myQueue.peek()==0) //if top of queue is at 0, remove from queue
{
myQueue.remove();
System.out.println("Customer removed");
}
else
//THIS IS WHERE I AM TRYING TO DECREASE THE VALUE IN THE TOP QUEUE
}
Integer is immutable, so wrap an int in your own class:
class Customer {
int time;
public Customer(int time) {
this.time = time;
}
// getter, setter
}
and define a corresponding Queue:
Queue<Customer> myQueue = new ...;
Instantiate a java.util.Timer; in the corresponding java.util.TimerTask, iterate through the Queue using a for-each loop, altering or removing each in turn:
for (Customer c : myQueue) { ... }
Your wanting to decrement a value stored in the Customer object that is located at the top of the queue.
The easiest way would be to add a method to reduce the serviceTime within the Customer class.
public decServiceTime() {
serviceTime--;
}
Looking at the value associated to the Customer object sitting in the queue you can perform the actions necessary.
Also if you have any questions you should first try sending me, your TA an email. =)
Related
My question is how I would implement multithreading to this task correctly.
I have a program that takes quite a long time to finish executing. About an hour and a half. I need to generate about 10,000 random and unique number codes. The code below is how I first implemented it and have it right now.
import java.util.Random;
import java.util.ArrayList;
public class Main
{
public static void main(String[] args) {
Random random = new Random();
// This holds all the codes
ArrayList<String> database = new ArrayList<>();
int counter = 0;
while(counter < 10000){
// Generate a 10 digit long code and append to sb
StringBuilder sb = new StringBuilder();
for(int i = 0; i < 10; i++){
sb.append(random.nextInt(10));
}
String code = String.valueOf(sb);
sb.setLength(0);
// Check if this code already exists in the database
// If not, then add the code and update counter
if(!database.contains(code)){
database.add(code);
counter++;
}
}
System.out.println("Done");
}
}
This of course is incredibly inefficient. So my question is: Is there is a way to implement multithreading that can work on this single piece of code? Best way I can word it is to give two cores/ threads the same code but have them both check the a single ArrayList? Both cores/ threads will generate codes but check to make sure the code it just made doesn't already exist either from the other core/ thread or from itself. I drew a rough diagram below. Any insight, advice, or pointers is greatly appreciated.
Using a more appropriate data structure and a more appropriate representation of the data, this should be a lot faster and easier to read, too:
Set<Long> database = new HashSet<>(10000);
while(database.size() < 10000){
database.add(ThreadLocalRandom.current().nextLong(10_000_000_000L);
}
Start with more obvious optimizations:
Do not use ArrayList, use HashSet. ArrayList contains() time complexity is O(n), while HashSet is O(1). Read this question about Big O summary for java collections framework. Read about Big O notation.
Initialize your collection with appropriate initial capacity. For your case that would be:
new HashSet<>(10000);
Like this underlying arrays won't be copied to increase their capacity. I would suggest to look/debug implementations of java collections to better understand how they work under the hood. Even try to implement them on your own.
Before you delve into complex multithreading optimizations, fix the simple problems - like bad collection choices.
Edit: As per suggestion from #Thomas in comments, you can directly generate a number(long) in the range you need - 0 to 9_999_999_999. You can see in this question how to do it. Stringify the resulting number and if length is less than 10, pad with leading zeroes.
Example:
(use ConcurrentHashMap, use threads, use random.nextLong())
public class Main {
static Map<String,Object> hashMapCache = new ConcurrentHashMap<String,Object>();
public static void main(String[] args) {
Random random = new Random();
// This holds all the codes
ArrayList<String> database = new ArrayList<>();
int counter = 0;
int NumOfThreads = 20;
int total = 10000;
int numberOfCreationsForThread = total/NumOfThreads;
int leftOver = total%NumOfThreads;
List<Thread> threadList = new ArrayList<>();
for(int i=0;i<NumOfThreads;i++){
if(i==0){
threadList.add(new Thread(new OneThread(numberOfCreationsForThread+leftOver,hashMapCache)));
}else {
threadList.add(new Thread(new OneThread(numberOfCreationsForThread,hashMapCache)));
}
}
for(int i=0;i<NumOfThreads;i++){
threadList.get(i).start();;
}
for(int i=0;i<NumOfThreads;i++){
try {
threadList.get(i).join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for(String key : hashMapCache.keySet()){
database.add(key);
}
System.out.println("Done");
}}
OneThread:
public class OneThread implements Runnable{
int numberOfCreations;
Map<String,Object> hashMapCache;
public OneThread(int numberOfCreations,Map<String,Object> hashMapCache){
this.numberOfCreations = numberOfCreations;
this.hashMapCache = hashMapCache;
}
#Override
public void run() {
int counter = 0;
Random random = new Random();
System.out.println("thread "+ Thread.currentThread().getId() + " Start with " +numberOfCreations);
while(counter < numberOfCreations){
String code = generateRandom(random);
while (code.length()!=10){
code = generateRandom(random);
}
// Check if this code already exists in the database
// If not, then add the code and update counter
if(hashMapCache.get(code)==null){
hashMapCache.put(code,new Object());
counter++;
}
}
System.out.println("thread "+ Thread.currentThread().getId() + " end with " +numberOfCreations);
}
private static String generateRandom(Random random){
return String.valueOf(digits(random.nextLong(),10));
}
/** Returns val represented by the specified number of hex digits. */
private static String digits(long val, int digits) {
val = val > 0 ? val : val*-1;
return Long.toString(val).substring(0,digits);
}
}
So for a lab in my CS class, I have to simulate an arena where there are contestants, and I want to loop through an ArrayList in a nested for loop within a while loop to basically go through the list over and over until all contestants are dead. I tried using both an ArrayList and a CopyOnWriteArrayList for iterating through the list, but I can't seem to get the solution just right.
Here is what i need the program to do essentially:
"In our RPG a set of contestants are to be placed into an arena to battle one
another. The area should contain two of each of the classes described below.
We should be able to get a description of the arena with everyone in it and
the beginning and between each round. Contestants that are dead should be
described as such. In each round, all contestants in the arena are given a turn
to act, in which they will be able to attack if possible. When anyone takes
damage, it should be announced who took how much, of what kind of damage,
from who. After a round, if there is only one contestant left standing, they are
to be named the victor. If no one is alive, pick a winner at random from the
last to die."
Here is the sample of the code actually using the list.
import java.util.Random;
import java.util.ArrayList;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.Collections;
import java.util.Iterator;
public class ArenaSim
{
public static void main(String[] args)
{
Berserker b1 = new Berserker("Jimmy");
Warrior w1 = new Warrior("Paco");
WildMage wm1 = new WildMage("Potato");
Berserker b2 = new Berserker("Tonto");
Warrior w2 = new Warrior("Bennett");
WildMage wm2 = new WildMage("Cletis");
Contestant winner = null;
int winnerHP = 0;
CopyOnWriteArrayList<Contestant> contestants = new CopyOnWriteArrayList<Contestant>();
contestants.add(b1);
contestants.add(w1);
contestants.add(wm1);
contestants.add(b2);
contestants.add(w2);
contestants.add(wm2);
Collections.shuffle(contestants);
Iterator<Contestant> iter = contestants.iterator();
while(iter.hasNext())
{
Contestant current = iter.next();
if(current.isDead() == false)
{
System.out.println();
System.out.println(current.getName() + " prepares to attack!");
current.attack(contestants);
System.out.println();
if (current.getHP() > winnerHP)
{
winner = current;
winnerHP = current.getHP();
}
contestants.add(current);
}
}
System.out.println("All contestants have been defeated!");
System.out.println(winner.getName() + " wins the match!");
}
}
The removal of the items is handled within the particular item when they take "damage", so if they have an HP of 0 or less, it removes the item itself from the list passed into it.
Thanks for any help!
I'm working on the hotel program and I have a problem with the my Queue class.
I need to create queue object in my program to add to queue and take from queue. Every time a name is added to a room it should use the queue object method to add the customer’s name to the queue. When the user selects to display the names of the first 3 customers my code should remove them from the queue one by one (first in first out) and display them as they are removed.
The queue should be based on an array. When the queue items reach the end of the array they should be added to the start or the array. If the queue becomes full the oldest queue item should be automatically removed and displayed.
The problem at the moment is when the end reaches 5 it should push the first input and take the last input and move it to the front of an array. Also please note the Queue must be based on string array. Please see the code i have so far, maybe some of you can help?
public class Queue {
static String qitems[] = new String[7];
static int front = 0, end = 0;
void addqueue(String name) {
System.out.println("Enter Queue Item :");
qitems[end] = name;
end++;
if(end==5){
takequeue(name);
}
}
void takequeue(String name) {
qitems[front]=name;
if (end > front) {
System.out.println("Item taken :" + qitems[front]);
front++;
} else {
System.out.println("Empty queue");
}
}
void displayqueue() {
System.out.println("Queue display: ");
for (int look = front; look < end; look++) {
System.out.println(" " + qitems[look]);
System.out.println("end"+end);
}
System.out.println("");
}
The addqueue() seems to have a logical flaw. Value of end gets increased by 1 before you check if(end==5). When the value of end becomes 6, the if statement is ignored, the takequeue() method is not invoked and you face the problem. To solve this, either add the if statement before end++ as
void addqueue(String name){
System.out.println("Enter Queue Item :");
qitems[end] = name;
if(end==5){
takequeue(name);
}
end++;
}
Or check for end>=5 rather than end==5 as:
void addqueue(String name){
System.out.println("Enter Queue Item :");
qitems[end] = name;
end++;
if(end>=5){
takequeue(name);
}
}
P.S. Please be more precise and clearer while asking a question from next time by using proper punctuation in your question description. Also see the How to ask questions section in the FAQ.
I've been working away at this problem for the past 10-12 hours, and was wondering if you guys could help me debug/point me in the right general direction. The object of the program is to simulate a fast food store queue-line, which I'm attempting to accomplish using:
PriorityQueue (FIFO) data structure
I've consulted with colleagues, on-campus tutoring services, professors and the given course textbook: "Java How To Program: Deitel & Deitel" to no avail.
The provided pseudocode for the problem is as follows (I'm not trying to get you to do it for me):
BigBurger Inc. wants to see if having a single person at the counter both to take orders and to serve them is feasible. At each BigBurger, customers will arrive and get in line. When they get to the head of the line they will place their order, which will be assembled and served to them. Then they will leave the BigBurger and the next person in line will be able to order.
We need to know how long a customer may be forced to wait before he or she can place an order. Given a script that lists each customer for a typical day, we want to calculate the maximum customer waiting time. Each customer in the script is characterized by an arrival time (measured in minutes after the store opened) and a service duration (the number of minutes between ordering and getting the food).
Create a class BigBurger that contains method maxWait that is given a int[] arrival and a int[] service describing all the customers and returns the maximum time spent by a customer between arriving and placing the order. Corresponding elements of arrival and service refer to the same customer, and they are given in the order in which they arrive at the store (arrival is in non-descending order).
If multiple customers arrive at the same time they will all join the line at the same time, with the ones listed earlier ahead
of ones appearing later in the list.
Definition
Class:
BigBurger
Method:
maxWait
Parameters:
int[], int[]
Returns:
int
Method signature:
int maxWait(int[] arrival, int[] service)
(be sure your method is public)
Constraints-
arrival will contain between 1 and 50 elements inclusive-
service will contain the same number of elements as arrival-
the elements of arrival will be in non-decreasing order-
each element of arrival will be between 1 and 720 inclusive-
each element of service will be between 1 and 15 inclusive
Examples
{3,3,9}
{2,15,14}
Returns: 11
Two customers arrive at time 3. The first one waits 0 time, orders, and is served after 2 minutes, leaving at time 5. The second one then orders and is served at time 20. Meanwhile a customer arrives at time 9 and waits until the second customer leaves. This last customer then orders at time 20, and is served and leaves at time 20+14 = 34. The first customer waited 0 minutes, the second waited 2 minutes (from time 3 to time 5), and the last customer waited 11 minutes (from time 9 to time 20).
I have researched for example on the net, usually arrival time is calculated using system nano time or using a random method, but here in this case the arrival time and service time is already provided in the examples and I have to calculate the total wait time of each customer. Please guide me through this as I am new to coding.
The issues I'm experiencing:
Unable to print maxWaitTime for the customer when I call return maxWaitTime in the method maxWait(int[], int[])
Here is my code:
import java.util.*;
public class QueueProgram
{
static int[] arrival = {3,3,9};
static int[] service = {2,15,14};
int waitTime;
int finishTime;
int serviceTime;
static int index;
Queue<Integer> Customers = new LinkedList<Integer>();
public int maxWait(int[] arrival, int[] service)
{
//this.arrival = arrival;
//this.service = service
int maxWaitTime = 0;
int[]finishTime = new int[arrival.length];
for(int i=0; i<arrival.length;i++)
{
int startTime;
index = i;
if(index == 0)
{
startTime = arrival[index];
System.out.println(startTime);
}
else
{
startTime = Math.max(arrival[i],finishTime[i-1]);
}
finishTime[i] = startTime + service[i];
waitTime = finishTime[i] - service[i] - arrival[i];
if(waitTime > maxWaitTime)
{
maxWaitTime = waitTime;
}
}
return maxWaitTime;
}
public static void main(String[] args)
{
QueueProgram q = new QueueProgram();
q.maxWait(arrival, service);
}
}
import java.util.*;
public class QueueProgram
{
static int[] arrival = {3,3,9};
static int[] service = {2,15,14};
int waitTime;
int finishTime;
int serviceTime;
static int index;
Queue<Integer> Customers = new LinkedList<Integer>();
public int maxWait(int[] arrival, int[] service)
{
//this.arrival = arrival;
//this.service = service
int maxWaitTime = 0;
int[]finishTime = new int[arrival.length];
for(int i=0; i<arrival.length;i++)
{
int startTime;
index = i;
if(index == 0)
{
startTime = arrival[index];
//System.out.println(startTime);
}
else
{
startTime = Math.max(arrival[i],finishTime[i-1]);
}
finishTime[i] = startTime + service[i];
waitTime = finishTime[i] - service[i] - arrival[i];
if(waitTime > maxWaitTime)
{
maxWaitTime = waitTime;
}
}
return maxWaitTime;
}
public static void main(String[] args)
{
QueueProgram q = new QueueProgram();
q.maxWait(arrival, service);
System.out.println("Maximum wait time is: " + q.maxWait(arrival, service));
}
}
variable index is redundant, i already represents array index. Secondly, waitTime can be calculated as finshTime[i-1]-arrival[i], no need to calculate startTime. Lesser operations better space and time complexity.
try this:
for(int i=0; i<arrival.length;i++)
{
if(i != 0) {
waitTime = finishTime[i-1] - arrival[i];
if(waitTime > maxWaitTime)
{ maxWaitTime = waitTime;}
}
finishTime[i] = arrival[i] + service[i];
}
I am kind of learning concepts of Random number generation & Multithreading in java.
The idea is to not generating a repeated random number of range 1000 in a particular millisecond (Considering, not more than 50 data, in a multithreaded way will be processed in a millisecond). So that list of generated random number at the specific time is unique. Can you give me any idea as i am ending up generating couple of repeated random numbers (also, there is a considerable probability) in a particular milli second.
I have tried the following things where i failed.
Random random = new Random(System.nanoTime());
double randomNum = random.nextInt(999);
//
int min=1; int max=999;
double randomId = (int)Math.abs(math.Random()* (max - min + 1) + min);
//
Random random = new Random(System.nanoTime()); // also tried new Random();
double randomId = (int)Math.abs(random.nextDouble()* (max - min + 1) + min);
As I am appending the timestamp that is being generated, in a multithreaded environment i see the same ids (around 8-10) that is being generated (2-4 times) for 5000+ unique data.
First, you should use new Random(), since it looks like this (details depend on Java version):
public Random() { this(++seedUniquifier + System.nanoTime()); }
private static volatile long seedUniquifier = 8682522807148012L;
I.e. it already makes use of nanoTime() and makes sure different threads with the same nanoTime() result get different seeds, which new Random(System.nanoTime()) doesn't.
(EDIT: Pyranja pointed out this is a bug in Java 6, but it's fixed in Java 7:
public Random() {
this(seedUniquifier() ^ System.nanoTime());
}
private static long seedUniquifier() {
// L'Ecuyer, "Tables of Linear Congruential Generators of
// Different Sizes and Good Lattice Structure", 1999
for (;;) {
long current = seedUniquifier.get();
long next = current * 181783497276652981L;
if (seedUniquifier.compareAndSet(current, next))
return next;
}
}
private static final AtomicLong seedUniquifier
= new AtomicLong(8682522807148012L);
)
Second, if you generate 50 random numbers from 1 to 1000, the probability some numbers will be the same is quite high thanks to the birthday paradox.
Third, if you just want unique ids, you could just use AtomicInteger counter instead of random numbers. Or if you want a random part to start with, append a counter as well to guarantee uniqueness.
This class will allow you to get nonrepeating values from a certain range until the whole range has been used. Once the range is used, it will be reinitialized.
Class comes along with a simple test.
If you want to make the class thread safe, just add synchronized to nextInt() declaration.
Then you can use the singleton pattern or just a static variable to access the generator from multiple threads. That way all your threads will use the same object and the same unique id pool.
public class NotRepeatingRandom {
int size;
int index;
List<Integer> vals;
Random gen = new Random();
public NotRepeatingRandom(int rangeMax) {
size = rangeMax;
index = rangeMax; // to force initial shuffle
vals = new ArrayList<Integer>(size);
fillBaseList();
}
private void fillBaseList() {
for (int a=0; a<size; a++) {
vals.add(a);
}
}
public int nextInt() {
if (index == vals.size()) {
Collections.shuffle(vals);
index = 0;
}
int val = vals.get(index);
index++;
return val;
}
public static void main(String[] args) {
NotRepeatingRandom gen = new NotRepeatingRandom(10);
for (int a=0; a<30; a++) {
System.out.println(gen.nextInt());
}
}
}
If I understand your question correctly, multiple threads are creating their own instances of Random class at the same time and all threads generate the same random number?
Same number is generated, because all random instances where created at the same time, i.e. with the same seed.
To fix this, create only one instance of Random class, which is shared by all threads so that all your threads call nextDouble() on the same instance. Random.nextDouble() class is thread safe and will implicitly update its seed with every call.
//create only one Random instance, seed is based on current time
public static final Random generator= new Random();
Now all threads should use the same instance:
double random=generator.nextDouble()