How to avoid loop in this code - java

I am sending prices to customers (10000+) but below code has loop that causes delays in the process for customers waiting for calculations.
PriceVisibleForCustomer = Price + CustomerMargin
Price - changing every 300ms - sent from central store, not related to customer instance
CustomerMargn - some plus or minus amount that is resulting from customer agreement/segment/administrator decision etc. It doesnt change during customer http session, I can keep it in memory
Customer - he takes part in the process after he logs in, he should see rapidly changing prices of 8 products.
Maybe I need some more technology ? I have Spring 3/4, Java, Weblogic and i could create even separate webapp for this task for providing calculated prices.
I thought about threads in Java but 10000+ customers would mean too many threads wouldnt it ? How to change this code? Maybe I should change architecture but how?
/**
* Sends prices to customer. This method is called very often (300ms) as prices are changing in real time.
* Customer should see prices also each 300ms
* #param productId - id of a product that prices will be calculated
* #param productIdToPriceMap
* #param customerIdToMarginMap - this map is changed every time customer logs in or logs out
*/
private static void sendPricesToCustomers(Long productId,
Map<Long, BigDecimal> productIdToPriceMap,
Map<Long, BigDecimal> customerIdToMarginMap) {
//This loop is blocking last customer from receiving price until all other customers wil have theri prices calculated. I could create threads, 10000+ customers will be logged in, I cant create so much threads... can I?
for (Long customerId: customerIdToMarginMap.keySet()){
BigDecimal customerMargin = customerIdToMarginMap.get(customerId);
BigDecimal priceResult = productIdToPriceMap.get(productId).add(customerMargin);
//send priceResult to websocket
}
}

Here is a simple example of the Listener pattern, I am not sure if this approach will work for you but just throwing out some ideas ...
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Vector;
import javax.swing.Timer;
public class Demo {
public static Product[] PRODUCTS = new Product[]{
new Product("Computer", 400),
new Product("Desk", 800),
new Product("Chair", 70),
new Product("Printer", 300),
new Product("Television", 200)
};
public static void main(String[] args) throws InterruptedException {
Customer john = new Customer("John", 3);
john.addProduct(PRODUCTS[1]);
john.addProduct(PRODUCTS[2]);
john.addProduct(PRODUCTS[3]);
Customer mary = new Customer("Mary", 2);
mary.addProduct(PRODUCTS[1]);
mary.addProduct(PRODUCTS[2]);
mary.addProduct(PRODUCTS[4]);
Thread.sleep(10000);
System.exit(0);
}
}
interface IPriceListener {
public void priceChanged(Product product, int price);
}
class Customer implements IPriceListener {
String _name;
int _margin;
Vector<Product> _products = new Vector<Product>();
public Customer(String name, int margin){
_name = name;
_margin = margin;
}
public void addProduct(Product product){
_products.add(product);
product.addListener(this);
}
public void priceChanged(Product product, int price) {
System.out.println("[" + _name + "][" + _products.get(_products.indexOf(product)).getName() + "][" + price + "][" + (price + _margin) + "]");
}
}
class Product implements ActionListener {
private int _startingPrice;
private int _currentPrice;
private String _name;
private Timer _timer;
private Vector<IPriceListener> _listeners = new Vector<IPriceListener>();
public Product(String name, int price) {
_name = name;
_startingPrice = _currentPrice = price;
_timer = new Timer(300, this);
_timer.start();
}
public void addListener(IPriceListener listener) {
_listeners.add(listener);
}
public void removeListener(IPriceListener listener){
_listeners.remove(listener);
}
private void notifyListeners() {
for(IPriceListener listener : _listeners){
listener.priceChanged(this, getCurrentPrice());
}
}
public void actionPerformed(ActionEvent e) {
_currentPrice = _startingPrice + (int)(Math.random() * (5 - (-5))) + (-5);
notifyListeners();
}
public final String getName() {
return _name;
}
private synchronized final int getCurrentPrice() {
return _currentPrice;
}
}

One way to handle this is to create a single thread whose job is to consume priceResults off a queue and send them down the websocket (I'm assuming you have only one websocket). Your loop would then push priceResults onto the queue every 300ms without blocking the websocket thread. See ConcurrentLinkedQueue javadoc.
Edit:
To avoid the delay between finishing the current loop through customerIdToMarginMap and beginning to loop through the next update, here are some options:
Keep the queue concept and create a fixed thread pool where each thread pulls the next customerId/productIdToPriceMap/customerIdToMarginMapoff the queue. If you have four threads and 10,000 records, each thread will only have to process 2,500 records, thereby starting on the next 300ms data push 4 times earlier than your current implementation. Increase thread count as you find necessary for performance.
Keep my original queue concept but change the way you receive the price updates. The reason you need to loop is because you're getting pricing updates for every customer at the same time. If you can instead e.g. create a threaded listener for a group of customers that receives a customerIdToMarginMap containing only customerIds it's meant to handle, the iteration time will be significantly decreased.

Related

Should I use atomic integer or sync

I've got a little confused about using atomic/volatile/sync in my code.
Let's say I have an object of book info in a bookstore and for example, it may happen that two threads want to take the same book while the amount in the inventory is only 1, how can I promise that only one thread will take the book?
do I have to use synchronize?
BookInventoryInfo:
package bgu.spl.mics.application.passiveObjects;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Passive data-object representing a information about a certain book in the inventory.
*
* <p>
*
*/
public class BookInventoryInfo {
//The title of the book, his amount in the inventory and the price
private String bookTitle;
private AtomicInteger amountInInventory;
private int price;
public BookInventoryInfo(String bookTitle, int amountInInventory, int price) {
this.bookTitle = bookTitle;
this.price = price;
this.amountInInventory = new AtomicInteger(amountInInventory);
}
/**
* Retrieves the title of this book.
* <p>
* #return The title of this book.
*/
public String getBookTitle() {
return this.bookTitle;
}
/**
* Retrieves the amount of books of this type in the inventory.
* <p>
* #return amount of available books.
*/
public int getAmountInInventory() {
return this.amountInInventory.get();
}
/**
* Retrieves the price for book.
* <p>
* #return the price of the book.
*/
public int getPrice() {
return this.price;
}
public void reduceAmountInInventory() {
this.amountInInventory.decrementAndGet();
}
}
The way I want to take the book:
if(book.getAmountInInventory > 0)
{
book.amountInInventory--
}
You should use synchronized as using AtomicInteger isn't as simple as it might appear at first glance. While individual operations on AtomicInteger are thread safe, using multiple operations might not be. Your example is a good one. say you have
// say it start at 1
Thread1: if(book.getAmountInInventory > 0)
Thread2: if(book.getAmountInInventory > 0)
Thread1: book.amountInInventory--
Thread2: book.amountInInventory--
The amount is now -1.
If you use synchronized it is much simpler to hold the lock for the whole operation
synchronized (book) {
if(book.getAmountInInventory > 0) // no chance for a race condition here.
{
book.amountInInventory--
}
An AtomicInteger isn't sufficient here. While it would allow you to decrement the number of copies in the inventory atomically, that isn't enough - you don't need to just decrement it atomically, you also need to add some custom logic.
I'd use a plain old int, and protect its modification with explicit synchronized blocks or methods:
public class BookInventoryInfo {
private String bookTitle;
private int amountInInventory;
private int price;
public synchronized void checkOut() {
if (amountInInventory <= 0) {
throw new BookCheckoutException("No book in inventory");
}
amountInInventory--;
}
// All the other methods...
}
As an alternative to synchronization, you can also use a compareAndSet:
int a = book.amountInventory.get();
if (a > 0) {
boolean updated = book.amountInInventory.compareAndSet(a, a - 1);
}
This will only decrement the value of amountInInventory if its value is still a when you come to update it. The return value of compareAndSet indicates whether the value was changed or not.
You can wrap this in a loop, something like:
while (true) {
int a = book.amountInventory.get();
if (a == 0) {
return false; // To mean "no book in inventory";
}
if (book.amountInInventory.compareAndSet(a, a - 1)) {
return true; // To mean "there was a book in inventory, and it was removed".
}
}

How to erase a current object using a function | Java

I am trying to make an erase function to delete the teams of the tournament using the team code (value c in the constructor). Firstly I want to check if that team exists in the objects I made in the main method. Is that possible to do that using an if statement?
Exercise:
Create a java application that stores data for various football teams. Each team has a name, a code and the current points in the championship. In your class create methods for registering new teams, erasing existing teams using their code and showing a list for all the teams currently active in the championship
package assignment.exercise4;
public class Data {
private String name = "";
private int code = 0;
private static int register;
private int erase;
private int currentpoints = 0;
public Data(int c, int points, String n) { //constructor
code = c;
this.currentpoints = points;
name = n;
}
public void Erase(int c)
{
code = c;
if(code != 0)
System.out.println("Team with Code: "+code+" has been erased" );
else
System.out.print("Team with code "+code+" does not exist!");
}
public void Register(String newTeam,int code)
{
name = newTeam;
this.code = code;
System.out.println("New Team " + name + " registered with code " + code);
}
public void print()
{
System.out.println("Team name: " + name + "\nTeam code: " + code + "\nTeam points: " + currentpoints + "\n");
}
}
/*
public static void main(String[] args) {
System.out.println("\nList of Teams: \n");
Data t1 = new Data(110,42,"Juventus");
Data t2= new Data(105,45,"Manchester City");
Data t3= new Data(240,50,"Barcelona");
Data t4= new Data(122,36,"Arsenal");
Data Team = new Data(0,0,""); //use for erase
t1.print();
t2.print();
t3.print();
t4.print();
System.out.println("Teams erased: \n");
Team.Erase(110);
Team.Erase(122);
Team.Erase(0);
System.out.println("\n\nTeams Registered: \n");
t1.Register("Real madrid", 11);
t1.Register("Atletico Madric", 112);
}
}
*/
What are you trying to erase the teams from?
If they were in a list, for example...
Data t1 = new Data(110,42,"Juventus");
Data t2= new Data(105,45,"Manchester City");
Data t3= new Data(240,50,"Barcelona");
Data t4= new Data(122,36,"Arsenal");
List<Data> teams = Arrays.asList(t1, t2, t3, t4);
...you could create a list with a team erased like this...
public List<Data> erase(List<Data> team, int id) {
return team.stream()
.filter(t -> t.getId() != id)
.collect(Collectors.toList());
}
So...
List<Data> remainingTeam = erase(team, 122); // Removes Arsenal
...would remove the first element from the list
I will not answer this to elaborately since it is homework. I will try to give you a hint though.
If you have a team and want to do something with it. Otherwise you just have a team which just stays there in a particular scope (if you do not know what scope is, look it up!). If you have a team you most likely want do do something with it. In this case you seem to want to store information about the teams to use in a championship. Important to note here is that the teams are not the focus here. The real focus is the Championship. The teams are just a part of the championship. There can still be a championship even if all teams does not choose to participate. But you want all teams choosing to participate to be registered to this particular championship (eg UEFA Champions League).
This leads to something called aggregate or association depending on how hard you want to tie the object to the championship. However you do probably not need to pursue these terms any further at this point. What is important to remember is that there is an "has a" relation between the championship and the teams. The championship "has a" collection of participating teams. This is normally reflected in this way in code,
public class Championship {
private Team[] teams; // Or List<Team>, Collection<Team>, HashMap<Team>, ...
}
The Championship can then have methods for registering a team, removing a team, updating status, etc...
public void register(Team t) {
if (numberOfTeams < teams.length) {
teams[numberOfTeams] = t; // Index starts at zero
numberOfTeams++;
} else {
throw new IndexOutOfBoundsException("The list is full. " +
"No more teams may be registered!")
}
}
Even though the function erasing a team was requested, I believe I will not write it down. This design is so different from your original intent, so that writing the erase function will likely solve your complete homework. However, you do actually not have to erase the team it is perfectly possible to just overwrite the position with the next team as,
teams[i] = teams[i+1];
Hope this helps!
Short answer:
public void erase(int id) {
// who needs an if statement, if we can use predicates?
teams.removeIf(team -> team.getId() == id);
}
But this will not work with your current code. Your current code misses the container for your teams.
Longer answer:
For the fun of it. Solving your homework:
class Team {
int id;
String name;
int points;
Team(int id, String name, int points) {
this.id = id;
this.name = name;
this.points = points;
}
#Override
public String toString() {
// ugly formatted... another homework? ;-)
return "Team '" + name + "' (" + id + "): " + points;
}
}
Note, that I will not add any getter or setter, nor will I care about visibility here. I will leave that as another homework for you.
class Championship {
List<Team> teams = new ArrayList<>();
void register(Team team) {
teams.add(team);
}
void erase(int id) {
teams.removeIf(team -> team.id == id);
}
#Override
public String toString() {
// for additional fun... sorted by descending points
return "=== Championship table ===\n"
+ teams.stream()
.sorted((o1, o2) -> Integer.compare(o2.points, o1.points))
.map(Objects::toString)
.collect(Collectors.joining("\n"));
}
}
Somewhere else:
public static void main(String[] args) {
Championship championship = new Championship();
championship.register(new Team(1, "not the best ones", 3));
championship.register(new Team(2, "The better ones", 7));
championship.register(new Team(3, "The winners", 11));
System.out.println(championship);
championship.erase(3);
System.out.println(championship);
}
Output:
=== Championship table ===
Team 'The winners' (3): 11
Team 'The better ones' (2): 7
Team 'not the best ones' (1): 3
=== Championship table ===
Team 'The better ones' (2): 7
Team 'not the best ones' (1): 3
Too much of information? Just start with something like a championship-class or at least use a collection of Teams (e.g. List<Team>).
By the way... Do not deliver this solution as your homework, except you understand what is going on and you can explain it with your own words. Otherwise you are only betraying yourself.

Java: counting number of times data appears in a class

I know how to count most things when it comes to Java, but this has either stumped me a lot, or my brain is dying. Anyway, I have a class called "Jobs", and within that class is a String variable called "day". Multiple new Jobs have been created already (exact number is unknown), and now I need to query and find out how many Jobs are on x day. I assume it would be easy enough with a while loop, but I don't know how to create one that looks through Jobs as a whole rather than one specific one.
The Job data was created by reading a file (the name of which is jobFile) via a Scanner.
public class Job_16997761 {
private int jobID; // unique job identification number
private int customerID; // unique customer identification number
private String registration; // registration number for vehicle for this job
private String date; // when the job is carried out by mechanic
private String day; // day of the week that job is booked for
private double totalFee; // total price for the Job
private int[] serviceCode; // the service codes to be carried out on the vehicle for the job
//Constructor
public Job_16997761(int jobID, int customerID, String registration,
String date, String day, double totalFee, int[] serviceCode) {
this.jobID = jobID;
this.customerID = customerID;
this.registration = registration;
this.date = date;
this.day = day;
this.totalFee = totalFee;
this.serviceCode = serviceCode;
}
Not sure why you are creating a dynamic instance of a job (eg. Job_16997761, it seems that each job has its own class). But when creating the jobs you can maintain a map that will have the number of jobs per day. Something like:
Map<String, Long> jobsPerDay=new HashMap<String,Long>();
Then when creating a new job you can simply increment the counter for each day:
jobsPerDay.put(day,jobsPerDay.get(day)!=null?jobsPerDay.get(day)++:1);
This way you will be able to get the number of jobs for a day by using: jobsPerDay.get(day)
Please note that you can use java.time.DayOfWeek instead of a String.
It's hard to tell you correct solution unless you give more details. You are saying you can write while loop so I will assume you have a collection of Job already.
int count = 0;
List<Job> jobs = readJobsFromFile();
for(Job job : jobs) {
if(job.getDay().equals(inputDay)){ //inputDay is day you have to find number of jobs on.
count++;
}
}
System.out.Println(count);
This is just one of the many ways and may not be that efficient, but this is one way you may consider (Before you edited your last post). Using an arrayList to contain all the Job objects and iterate through the objects.
import java.util.*;
public class SomeClass {
public static void main(String[] args)
{
Jobs job1 = new Jobs(1);
Jobs job2 = new Jobs(1);
Jobs job3 = new Jobs(2);
Jobs job4 = new Jobs(2);
Jobs job5 = new Jobs(2);
ArrayList<Jobs> jobList = new ArrayList<Jobs>();
jobList.add(job1);
jobList.add(job2);
jobList.add(job3);
jobList.add(job4);
jobList.add(job5);
System.out.println(numOfJobOnDayX(jobList, 2)); //Jobs which falls on day 2
}
public static int numOfJobOnDayX(ArrayList<Jobs> jobList, int specifiedDay)
{
int count=0;
for(int x=0; x<jobList.size(); x++) //May use a for-each loop instead
if(jobList.get(x).days == specifiedDay)
count ++;
return count;
}
}
OUTPUT: 3
Class for Jobs..
class Jobs
{
int days;
public Jobs(int days)
{
this.days = days;
}
}
For simplicity, I am not using any getter and setter methods. You may want to think about what data structure you want to use to hold your objects. Once again, I need to re-emphasize this may not be an efficient way, but it gives you some ideas some possibilities of doing the count.

Incrementing value in a Map (JAVA)

I'm having a problem with this home work assignment. I can handle the syntax, but not the logic. Could you provide me some tips.
What I'm trying to achieve is that the add method would increase the amount of products by using the increaseAmount method. Now it resets the value of amount to "1" every time I call the method. What makes this complicated is that I'm not allowed to use any other private variables than already used.
private Map<String, Purchase> shoppingCart = new HashMap<String, Purchase>();
public void add (String product, int price) {
Purchase purchase = new Purchase (product, 1, price);
//the line abowe returns the value back to 1 which I don't want.
if(shoppingCart.containsKey(product)) {
shoppingCart.put(product, purchase);
purchase.increaseAmount();
}
else {
shoppingCart.put(product, purchase);
The product constructor:
public Ostos(String product, int amount, int price) {
Code for the increaseAmount method:
private int amount;
public void increaseAmount() {
this.amount = (this.amount + 1);
Don't create a new purchase at the beginning only create it if it's not already there
public void add (String product, int price) {
if(shoppingCart.containsKey(product)) {
Purchase purchase = shoppingCart.get(product);
purchase.increaseAmount();
//You might have to put the purchase back into the cart I'm not sure
}
else {
Purchase purchase = new Purchase (product, 1, price);
shoppingCart.put(product, purchase);
}
You have to retrieve the value from shoppingCart and then increment the amount. You're never calling shoppingCart.get, so you're replacing the value each time by blindly putting the new purchase object into the map.

synchronize and merge messaging/data flow

It is about very common sensor data processing problem.
To synchronize and merge sensor data from different sources, I would like to implement it in Java without too complicated 3rd libs or framework.
Say, I define an object (O) which consists of, for example, 4 attributes (A1,..A4). The 4 attributes come from different data channels, e.g. socket channel.
The 4 attributes arrive generally in a rate of 1.0 ~ 2.0 Hz and their arrivals are independent from each other.
Once there are 4 attributes (A1, ..A4) coming at the same time (within a small time window, e.g. 100ms), then I construct a new object (O) from those 4 attributes.
a descriptive scenario is as follows.
the arrival time point of A1 ~ A4 is marked with *.
Objects O1 ~ U3 are constructed on the time point of t1, t2 and t3 respectively.
Some attributes arrives between t2 and t3, but are not complete for constructing an Object, therefore they
would be dropped and ignored.
A1 * * * *
A2 * * * *
A3 * * *
A4 * * * *
--------|------------|-----------------|----------> time
t1 t2 t3
O1 O2 O3
some requirements:
identify the time point a.s.a.p. to construct a object from the last incoming 4 attributes.
FIFO, O1 must be constructed before O2, and so on.
less locking in Java
drop data eventually if they are not complete to construct a object.
Some quick idea on implementation are:
store any incoming attributes in a FIFO queue of time-discrete buckets (each bucket contains 4 different attributes).
run an endless thread concurrently to check the FIFO queue (from the head of the queue) if any bucket is already filled with 4 different attributes. If yes, then construct an object and remove the bucket from the queue. If a bucket is not complete filled within a specific time window, it will be dropped.
any suggestion and correction is welcome!
This is unlikely to solve your problem, but it might point you in the right direction.
I would use Google Guava's MapMaker for a first attempt:
ConcurrentMap<Key, Bucket> graphs = new MapMaker()
.expireAfterAccess(100, TimeUnit.MILLISECOND)
.makeComputingMap(new Function<Key, Bucket>() {
public Bucket apply(Key key) {
return new Bucket(key);
}
});
This would create a map whose entries would disappear if they had not been accessed for 100 ms, and creates a new bucket when it is asked for.
What I can't work out is exactly what the Key would be :S What you're really after is the same kind of functionality in the form of a queue.
Here's another crazy idea:
use one single LinkedBlockingQueue to write values to from all sensors A1-A4
assign this queue to AtomicReference variable
create a timer task which will switch this queue with a new one at specified intervals (100ms)
fetch all data from the old queue and see if you have all data A1-A4
if yes, then create the object, otherwise drop everything
This is another way of doing it - it's just pseudocode though, you'll need to write it yourself :)
class SlidingWindow {
AtomicReference<Object> a1;
AtomicReference<Object> a2;
AtomicReference<Object> a3;
AtomicReference<Object> a4;
Queue<Long> arrivalTimes = new Queue(4);
public Bucket setA1(Object data) {
a1.set(data);
now = System.currentTimeInMillis()
long oldestArrivalTime = arrivalTimes.pop();
arrivalTimes.push(now);
if (now - oldestArrivalTime < 100) {
return buildBucket();
}
return null;
}
public Bucket setA2(Object data) { ...
...
private Bucket buildBucket() {
Bucket b = new Bucket(a1, a2, a3, a4);
a1.clear();
a2.clear();
a3.clear();
a4.clear();
return b;
}
}
You could do something like this, the get operation is blocking till data has arrived, the add operation is not blocking. The get operation could be optimized a bit so that you keep candidates in a paralell structure so that you don't need to iterate over all candidates when filtering out old items. Iterating over 4 items should however be fast enough.
import java.util.HashMap;
import java.util.Iterator;
import java.util.concurrent.LinkedBlockingQueue;
public class Filter<V> {
private static final long MAX_AGE_IN_MS = 100;
private final int numberOfSources;
private final LinkedBlockingQueue<Item> values = new LinkedBlockingQueue<Item>();
public Filter(int numberOfSources) {
this.numberOfSources = numberOfSources;
}
public void add(String source, V data) {
values.add(new Item(source, data));
}
public void get() throws InterruptedException {
HashMap<String, Item> result = new HashMap<String, Item>();
while (true) {
while (result.size() < numberOfSources) {
Item i = values.take();
result.put(i.source, i);
if (result.size() == numberOfSources) {
break;
}
}
//We got candidates from each source now, check if some are too old.
long now = System.currentTimeMillis();
Iterator<Item> it = result.values().iterator();
while (it.hasNext()) {
Item item = it.next();
if (now - item.creationTime > MAX_AGE_IN_MS) {
it.remove();
}
}
if (result.size() == numberOfSources) {
System.out.println("Got result, create a result object and return the items " + result.values());
break;
}
}
}
private class Item {
final String source;
final V value;
final long creationTime;
public Item(String source, V value) {
this.source = source;
this.value = value;
this.creationTime = System.currentTimeMillis();
}
public String toString() {
return String.valueOf(value);
}
}
public static void main(String[] args) throws Exception {
final Filter<String> filter = new Filter<String>(4);
new Thread(new Runnable() {
public void run() {
try {
filter.get();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
filter.add("a0", "va0.1");
filter.add("a0", "va0.2");
Thread.sleep(2000);
filter.add("a0", "va0.3");
Thread.sleep(100);
filter.add("a1", "va1.1");
filter.add("a2", "va2.1");
filter.add("a0", "va0.4");
Thread.sleep(100);
filter.add("a3", "va3.1");
Thread.sleep(10);
filter.add("a1", "va1.2");
filter.add("a2", "va2.2");
filter.add("a0", "va0.5");
}
}

Categories

Resources