Thursday, October 31, 2019

Java Float.MIN_VALUE is not negative!


While writing a function to return a the max vector late in evening I encountered the following assertion error for the code below. Just went home, thinking i am seeing something wrong since its late :-)

----

The shouldReturnMaxVector below fails with the following error
Expected: [2 .0,  -6 .0f,  -5 .0f]
Actual:   [2 .0f,1 .4e-45, 1 .4e-45]
----

    @Test
    public void shouldReturnMaxVector() throws Exception {
        float[] max = max(new float[]{Float.MIN_VALUE, Float.MIN_VALUE, Float.MIN_VALUE}, new float[]{2, -6, -5});
        assertThat(max, is(new float[]{2, -6, -5}));
    }


    public static float[] max(float[] v1, float[] v2) {
        return findByCompare(v1, v2, (x, y) -> x > y);
    }

    public static float[] findByCompare(float[] v1, float[] v2,
                                        BiFunction selector) {
        float[] result = new float[v1.length];
        for (int i = 0; i < v1.length; i++) {
            result[i] = selector.apply(v1[i], v2[i]) ? v1[i] : v2[i];
        }
        return result;
    }
--

Later i realized, Float.MIN_VALUE is not negative. The following stack overflow answer (https://bit.ly/2J6tKbI) provides a good explanation for the same.

Below is the answer from SO
--
The IEEE 754 format has one bit reserved for the sign and the remaining bits representing the magnitude. This means that it is "symmetrical" around origo (as opposed to the Integer values, which have one more negative value). Thus the minimum value is simply the same as the maximum value, with the sign-bit changed, so yes-Double.MAX_VALUE is the smallest possible actual number you can represent with a double.
I suppose the Double.MAX_VALUE should be seen as maximum magnitude, in which case it actually makes sense to simply write -Double.MAX_VALUE. It also explains why Double.MIN_VALUE is the least positive value (since that represents the least possible magnitude).
But sure, I agree that the naming is a bit misleading. Being used to the meaning Integer.MIN_VALUE, I too was a bit surprised when I read that Double.MIN_VALUE was the smallest absolute value that could be represented. Perhaps they thought it was superfluous to have a constant representing the least possible value as it is simply a - away from MAX_VALUE :-)
(Note, there is also Double.NEGATIVE_INFINITY but I'm disregarding from this, as it is to be seen as a "special case" and does not in fact represent any actual number.)
Here is a good text on the subject.
--

Wednesday, October 16, 2019

Java Lambda Expression Method Resolution

We have two build environments for release to production  - one we build and regularly test; other is maintained by the global build team that generates certified binaries for release.
We got a compilation issue in the environment maintained by the global team. The compilation is fine in our environments and release environment it fails. We looked at all tagging etc...no problem. Finally it came down to compiler version. We used javac -> 1.8.0_66-b17 and release environment uses  javac -> 1.8.0_05. The upgrade fixed the issue.
But, what did we code that has caught a bug in this range? Here it is.

Following are two overloaded methods that execute the given function in the context of a tenant.

public static R executeForTenant(String tenantId, Function function)

public static void executeForTenant(String tenantId, Consumer consumer)

public void loadPreferenceInto(String tenant, Configuration configuration)

The usage is as follows..

executeForTenant(tenant, (t) -> loadPreferenceInto(t, configuration));

This is ambiguous, compiler cannot determine which one to pick. The void-ness is also compatible with Function generic type R since the statement body is an expression.
So we changed the invocation to
executeForTenant(tenant, (t) -> { loadPreferenceInto(t, configuration); });

This {} ensures the statement body is not an expression. So it should pick Consumer parameter based  executeForTenant method.
The change worked in our environment but failed in release; obviously the bug was fixed in between the builds - 1.8.0_20 to be precise.
Lambda expression resolution (from above link)

A lambda expression (15.27) is potentially compatible with a functional interface type (9.8) if all of the following are true:
- The arity of the targeted type's function type is the same as the arity of the lambda expression.
- If the targeted type's function type has a void return, then the lambda body is either a statement expression (14.8) or a void-compatible block (15.27.2).
- If the targeted type's function type has a (non-void) return type, then the lambda body is either an expression or a value-compatible block (15.27.2).

Interesting ride, it has been for last 2 days....

Friday, December 16, 2016

Java HashMap - Infinite loop; another reason not use it in a non-thread safe way!

We are aware that HashMap in Java is not thread safe. Multithreaded usage may cause corruption of the data structures used by HashMap. This may result in loss of keys or incorrect values for keys.

I realized it's not just limited to that, following is the issue we faced in one of our legacy applications. The hash map (non-thread safe) usage resulted in an infinite loop.

I had been looking at CPU usage of the application, running on a 16 core box. CPU usage was 400%; 4 cores of 16 cores were busy. There was absolute zero external load on it. The top output of the same, is shown below


Following is the thread stack of the busy threads.


All of them are stuck in HashMap. The hash map put is in infinite loop.

JDK src code for HashMaphttp://www.docjar.com/html/api/java/util/HashMap.java.html

Review of the line 494 in JDK src code (thread stack shows the same) along with the excellent blog http://mailinator.blogspot.in/2009/06/beautiful-race-condition.html, the cause for the infinite loop can be understood.

Tuesday, September 01, 2015

A case for Bloom Filter

We provide cache as service to our users. Users can put elements into cache with a TTL. We needed to determine the performance of the cache in terms of the hit rate.

The hit rate can be low because of two factors - LRU in the cache and TTL of the element put by user. We needed to ensure that the hit rate is not low because of LRU - in that case we were ready to allocate more memory for the cache.

One of the ways to determine if the TTL caused removal of the element is to track all the keys in the the cache even if the elements were removed. 

Bloom filter is a good data structure to track the keys. We keep adding keys to the bloom filter. When a cache miss occurs, we check the bloom filter if the key was ever present. If it was, then the cache miss was caused by TTL. If it was not present then it was a real cache miss. 

Bloom filter will give an affirmative answer if an element was not present. Its probabilistic answer if the element was present - in our case this is acceptable since we will count additional cache miss due to TTL. It is acceptable because it is easy to tune TTL than cache.

Also we are adding elements for tracking and no removals - which also matches with the requirement of the bloom filter.

In summary, Bloom filter worked well for our case compared to other alternate set data structures. We were able to determine presence of an element with minimal possible bits and tune our cache performance.

Sunday, August 09, 2015

Port Unification with Netty in Proxy Mode

Serving requests - both HTTP and HTTPS on the same port had been a requirement in my scenario.This is called port unification.  I was using Netty to serve requests. One of the standard ways to handle the scenario is to use the approach described in PortUnificationHandler.

However, in my case, the Netty implementation was mimicking the behaviour of a proxy server. This means that a client will make a CONNECT request before any actual data request is sent. CONNECT request is always non-SSL - even if the protocol to follow is HTTPS.

The approach to use in this scenario is as follows:


Implement a ChannelInboundByteHandlerAdapter;  on inbound buffer update - check if the request is CONNECT request. In case of CONNECT request, pass on the incoming bytes to the next handler in the chain.

If its not a CONNECT request, do the SSL data encryption check and add the SSL handler to the chain if necessary. Before passing on the bytes to the next handler, the unification handler should remove itself from the chain.

Monday, July 20, 2015

Threading Race Deque

Following code has been causing problems at a various times and has sent me debugging in a lot of unrelated areas.

private final NavigableSet scenarios = new ConcurrentSkipListSet()

public void fireCompletedScenarios() {
        while (!scenarios.isEmpty()) {
            InMemoryScenarioRecord firstScenario = scenarios.first();
            if (firstScenario.completed()) {
                synchronized (completedScenarios) {
                    completedScenarios.offer(scenarios.pollFirst());
                }
                continue;
            }
            //exit when you find first uncompleted scenario
            break;
        }
    }

There is a navigable set of scenarios, ordered by scenario time. We pull out completed scenarios from it and add it to another queue. We break when we find the first incomplete scenario.

The issue I have been facing is - incomplete scenarios getting into the queue of completed scenarios. As usual, the case does not happen in local environment - happens in non-prod environments -under high load. Hence, it must be some race condition causing the issue.

Finally it stuck to me is the bug in the above code that manifests under high load. The bug is as follows:

The scenarios.first() just gives me access to the first scenario and does not remove it from the navigable set. After the completion check, pollFirst is called to remove it from the set.

This is the bug - under high load - the element returned by first and the element removed by pollFirst are not same!

There can be another incomplete scenario that came in to the set; to the top because it had lower scenario time; but arrived late into the set because of the asynchronicity that existed in this system. This resulted in adding a incomplete scenario returned by pollFirst to the completed queue!

huh! I fixed this over sight and learnt a valuable lesson !

Sunday, February 16, 2014

Farey Series

I have been managing to read the book Recreations in Theory of Numbers. A good informal book on Number Theory. Farey series is one of topics I wanted to write a program for. Following is the Groovy code of generating Farey series until the given value of the denominator.
def farey = {
    def a = 1, b = it, c = 1, d = it - 1;
    printf "%d/%d ", a, b
    while (c != 1 || d != 1) {
        printf "%d/%d ", c, d
        z = (int) ((it + b) / d)
        (a, b, c, d) = [c, d, z * c - a, z * d - b]
    }
}

farey(7)

Output: 
1/7 1/6 1/5 1/4 2/7 1/3 2/5 3/7 1/2 4/7 3/5 2/3 5/7 3/4 4/5 5/6 6/7 

Saturday, January 25, 2014

Learning OAuth 2.0

Source of truth for OAuth 2.0 is, of course, the RFC 6749. The language and explanation in RFC is very much comprehensible.
 
     +--------+                               +---------------+
     |        |--(A)- Authorization Request ->|   Resource    |
     |        |                               |     Owner     |
     |        |<-(B)-- Authorization Grant ---|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(C)-- Authorization Grant -->| Authorization |
     | Client |                               |     Server    |
     |        |<-(D)----- Access Token -------|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(E)----- Access Token ------>|    Resource   |
     |        |                               |     Server    |
     |        |<-(F)--- Protected Resource ---|               |
     +--------+                               +---------------+

OAuth 2.0 defines quite a few API endpoints. The RFC provides examples for the request and expected responses for these APIs.

One of the good ways to understand the RFC is build the OAuth endpoints and try out the samples mentioned in it. Apigee Edge support of OAuth 2.0 is a quick help here.

This github project oauth20_apigee contains the proxy and the postman client requests.

Apart from the RFC,following are two good resources about OAuth 2.0

Friday, December 13, 2013

brew install octave fails on OS X - Mountain Lion

Octave installation on Mountain Lion fails during the make install phase with the following error:
 make install
./plot.texi:3957: warning: node `Multiple Plot Windows' is prev for `Printing and Saving Plots' in menu but not in sectioning
 make[3]: *** [octave.info] Error 1
 make[2]: *** [install-recursive] Error 1
 make[1]: *** [install-recursive] Error 1
 make: *** [install] Error 2
The solution seems to be the manual patch indicated here: http://goo.gl/nq0H5b
In summary: --enable-docs=no makes it work.

Sunday, June 03, 2012

Post S2 I9100G ICS Upgrade: Only Samsung Logo Left?

I decided to upgrade my Samsung S2 I9100G from Gingerbread to ICS; used the software update on the phone to perform the upgrade; now my phone would boot and show the Samsung logo for eternity!

The only way to get the phone back to work is to revert to Gingerbread! This has to be done manually by downloading the firmware and installing it.

Thanks to this link , it provides a detailed explanation for doing the same.

Appreciate Samsung for such robust update release which only shows their logo after its applied!

Of course, I can visit the Samsung service center in Bangalore which is worse than their upgrade package!

Sunday, May 20, 2012

loadClass - JDK 1.6.0_18 vs JDK 1.6.0_27

Recently while implementing a custom class loader, I hit upon a issue related to loadClass method of the Classloader.  The custom classloader code of interest is below.

This classloader worked on JDK 6 Update 27 (dev env) but failed to work on JDK 6 Update 17 (test env).


Its a rare skill to write code in Java that  fails between minor revisions!! :-)

The class loader code was written looking at the Java source code for Classloader. This was the cause of the issue - the custom loader implementation did not adhere to the documented contract for the loadClass method.

The documentation of the loadClass method clearly states

Throws:
ClassNotFoundException - If the class could not be found

While the custom class loader method returns null if the class is not found! So why did it work in latest update of Java?  Following are the Classloader code snippets from the two JDK 6 updates that I have mentioned.

Jdk 1.6 Update 18


Jdk 1.6 Update 27


The if check c==null in the Update 27 made the loadClass method work even though it did not adhere to the documented contract.

The bottom line is to code against documented contract and not look at the implementation to write code!

Monday, February 06, 2012

Analytical Reasoning With Prolog

Last year, I solved the following analytical reasoning problem by hand. Post learning Prolog, I think this is a good problem to solve using a computer! I had a interesting experience doing so.

Problem:

Facts:
1: There are 5 villas in 5 different colors 
2: In each villa lives a person with a different nationality. 
3: These 5 owners drink a certain beverage, smoke a certain brand of cigar and keep a certain pet. 
4: No owner has the same pet, smoke the same brand of cigar or drink the same drink.
Hints:
1: The British lives in a red villa. 
2: The Swede keeps dogs as pets 
3: The Dane drinks tea 
4: The green villa is on the left of the white villa (it also means they are next door to each other) 
5: The green villa owner drinks coffee 
6: The person who smokes Pall Mall rears birds 
7: The owner of the yellow villa smokes Dunhill 
8: The man living in the villa right in the center drinks milk 
9: The Norwegian lives in the first villa 
10: The man who smokes Blend lives next to the one who keeps cats 
11: The man who keeps horses lives next to the man who smokes Dunhill 
12: The owner who smokes Blue Master drinks beer 
13: The German smokes Prince 
14: The Norwegian lives next to the blue villa 
15: The man who smokes Blend has a neighbor who drinks water.

The question is: who keeps the fish?

Prolog Solution:

The following is what i could come up with after serval iterations through code.


Answer to Puzzle:

Following is the output of the prolog program.

1,norwegian,yellow,water,dunhill,cat
2,dane,blue,tea,blend,horse
3,british,red,milk,pallmall,birds
4,german,green,coffee,prince,fish
5,swede,white,beer,bluemaster,dog

Hence the answer is German keeps the fish.


Monday, December 26, 2011

C#: Timer, Deferred Evaluation & GC

Following is the snippet of benign (at least by appearance) code that had been cause one of the bugs we faced recently.

The class schedules the given jobs on a timer. The start time for the jobs is around 10 hours from the point the scheduler Start is executed. The timer fires every 24 hrs periodically.

As unexpected, the timer never fired, not even once in production.

We did not face any issue related to this code in development environment, the only difference was that the delay time and period for the timer were shorter in the unit test.

Key suspect in such code behavior is GC. GC has high probability of execution in a long running process than a short running unit test.

The issue was indeed GC, the timer was being garbage collected hence the timer callback was not being executed.

Here is the detailed analysis of the code.
  •  The Loc 1 in the code is a Select expression which is implemented  by deferred execution.
  •  The Loc 2 in the code exists to ensure the Select is executed and timer is created/scheduled.
  •  The key issue with the code is no reference to the Timer object created is retained.  Hence, the Timer object is garbage collected.
  • Even though the Loc 1 seems to indicate that the reference to the Timer is assigned to the _timers field, it's not so. The _timers field holds the reference to the Select iterator. In other words, the lambda code itself.
GetType() on _timers will return System.Linq.Enumerable+WhereSelectListIterator`2 [System.Threading.TimerCallback,System.Threading.Timer]
  • If the timer is garbage collected, what is the observed behavior in the Dispose method of the JobScheduler ? 
The foreach loop actually creates new timers as a result of Select execution again and disposes them. 
So the current situation with the code is
  • Timer will not be fired if the GC runs.
  • Timer created will never be stopped by Dispose if the GC does not collect it.
The solution is to convert the output of the Select iterator using toList()or an equivalent method . This method not only forces eager evaluation but also creates a proper enumerable list of Timer objects - System.Collections.Generic.List`1[System.Threading.Timer]
This is the Gist of the the complete program to observe the issue/code behavior.


Sunday, December 11, 2011

Prolog: List Difference

Today I was implementing a Prolog program to find the difference between two lists.

Here is the problem statement and the expected output.

minus([1,2,3,4],[1,3],W).
W=[2,4]
yes

As a beginner in Prolog, I tend use the accumulator based approach to find the solution. Here is what I came up with spending some significant time at the Prolog interpreter and debugger.


minusAcc(L,[],_,L) :- !.
minusAcc([],_,A,A) :- !.
minusAcc([H|T],SL,A,W) :- \+memberchk(H,SL),!,
                            append([H],A,AL),
                            minusAcc(T,SL,AL,W).
minusAcc([_|T],SL,A,W) :- minusAcc(T,SL,A,W).
minus(L,SL,W) :- minusAcc(L,SL,[],W).

This program gives the expected output but does not preserve the order. It actually gives the output in the reverse order because of the inherent recursion in the program.  Following is output generated by this program.

minus([1,2,3,4],[1,3],W).
W=[4,2]
yes

Since, I wrote this routine for use in list sorting, the order did not matter and I decided to live with this program.

Meanwhile, I had a look at the implementation available on the web for the same purpose and I found the following program on stackoverflow very interesting.

minus(L,[],L) :- !.
minus([],_,[]) :- !.
minus([H|T],SL,W) :- memberchk(H,SL),!,minus(T,SL,W).
minus([H|T1],SL,[H|T2]) :- minus(T1,SL,T2).

This program gives the expected output and preserves the order too. This program also uses the classic accumulator (unlike mine) based approach, but here the result itself is the accumulator. I had to trace it on debugger for about 10 mins (this is my 2nd day on prolog) to understand the control flow. It was totally worth it!

Gem of a program! Made my weekend!

BTW, here is the gist of my Day 2 of Prolog using Seven Languages in Seven Weeks!


Sunday, November 13, 2011

Installing Io on Snow Leopard

Started on Seven Languages in Seven Weeks . Interesting set of 7 languages. Y'day reached Io - Day One. Had to do some googling around to get Io working on OS X.

In case you intend to do the same, here is the gist of the steps required to get going

  • Download Io source from git-repo
sudo git clone git://github.com/stevedekorte/io.git
  • Next step is to run the build.sh file in the cloned git  io directory. You might get the following error
~/software/io/libs/iovm/source/IoObject_inline.h:322: error: ‘always_inline’ function could not be inlined in call to ‘IoObject_rawGetSlot_’: recursive inlining

  • You need to modify the file  ~/software/io/libs/basekit/source/Common_inline.h change
#define NS_INLINE static __inline__ __attribute__((always_inline)) 
in the section #if defined(__APPLE__)  to
#define NS_INLINE static inline

        Friday, April 15, 2011

        Trying REBOL

        REBOL was the language I wanted to explore. Today I thought of writing a timezone converter application using REBOL.

        The application should be able to convert time from Indian timezone to Munich and Boston timezone. This conversion is related to my current project.

        With this weird requirement, I decided to use the most weird way to convert time. I decided to use the timeanddate.com timezone converter to do the conversion. As a result, the application has to make an HTTP GET call to this link and parse the resulting web page to find the converted time.

        Summarizing the Approach:
        1. Write a REBOL UI application that takes the Indian time as input
        2. On click of Convert, makes an HTTP call to the website with input given by the user.
        3. Parse the resulting web page and find the converted time.
        4. Show the converted time on the UI !!

        Here is the REBOL code for the application.
        This is a REBOL code for timezone convertor

        REBOL
        [
        Title: "Timezone Convertor IN to BOS & MUN"
        Author: "Srikanth Seshadri"
        ]

        t-time: to-string now/time

        time-get: func [inp-time tz] [
        page: reform [
        "http://www.timeanddate.com/worldclock/converted.html?hour="inp-time/hour"&min="inp-time/minute"&sec="inp-time/second"&p1=438&p2="tz]
        tzurl: to-url page
        tz-text: load/markup tzurl
        zone-found: false tg-time: now
        foreach item tz-text [
        if all [string? item zone-found ] [ tg-time: item break]
        if all [string? item any[ find item "(U.S.A" find item "(Germ"] ] [zone-found: true]
        ]
        tg-time
        ]

        gui: layout [
        backdrop effect [gradient 0x1 white]
        across
        h3 "Timezone Converter IN -> BOS & MUN" black return
        lab "Indian Time"
        t-time: field t-time 60x24 return
        tab
        button "Convert Time" [
        inp-time: (to-time t-time/text)
        if inp-time
        [
        boslbl/text: reform ["Time in Boston: " time-get inp-time 43]
        munlbl/text: reform ["Time in Munich: " time-get inp-time 83]
        show boslbl
        show munlbl
        ]
        ] keycode [#"^m"] return
        boslbl: h4 "[---------------------------------------------------------------------]" return
        munlbl: h4 "[---------------------------------------------------------------------]" return
        ]
        view center-face gui

        and the output

        This is most strange way to do timezone conversion, but the learnings and development was fun; all the effort was worth it!

        Monday, September 06, 2010

        World War II + India + Java

        While exploring Java timezone related API, it was a surprise to me that during the World War II, India(being colony of England) had Daylight Saving Time !

        This timezone was in effect from 1-Sept-1942 to 15-Oct-1945. Interestingly, this DST is supported by Java date time API.

        DateFormat indiaDtFmt = new SimpleDateFormat("dd/MM/yyyy HH'h'mm");
        DateFormat gmtDtFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        indiaDtFmt.setTimeZone(TimeZone.getTimeZone("Asia/Calcutta"));
        gmtDtFmt.setTimeZone(TimeZone.getTimeZone("GMT"));

        Date worldWarIIDate = indiaDtFmt.parse("02/02/1944 06h30");
        Date nonWorldWarIIDate = indiaDtFmt.parse("02/02/2006 06h30");

        System.err.println(gmtDtFmt.format(worldWarIIDate) +" GMT");
        System.err.println(gmtDtFmt.format(nonWorldWarIIDate) +" GMT");

        The above code produces the following output.

        1944-02-02 00:00:00 GMT
        2006-02-02 01:00:00 GMT

        So the during the World War II, India was in the timezone +4.30 GMT compared to the normal timezone of +5.30 GMT.

        This also mean the horoscopes of the people born in India during the World War II need to take this DST into consideration. These people include celebrities like Ilaiyaraaja,Azim Premji,Amitabh Bachchan etc.

        Obviously this well known to Astrologers.Here is one of the links for war-time correction for horoscopes. Another link for war time correction across the world.




        Saturday, July 31, 2010

        Auto Fare Converter


        New Auto fare in Bangalore is in effect from Aug 1, 2010. But, Autos have been given 2 month time period to change their meters.

        As a result, commuters are expected to know the fare conversion from old to new. Either trust the Auto Driver or have a print of the fare conversion table published.

        So I quickly wrote a mobile application to do the conversion. I wrote 2 versions, one android version and other Java ME (MIDP 2.0) application.




        Here are the links to the application installables





        Application Usage:
        1. Enter the current fare in the meter.
        2. Click Convert button.
        3. The amount you need to pay, the new fare, will be shown.


        Monday, July 26, 2010

        BMTC Bus Ticket Cost Calculation

        In a recent travel through BMTC bus to my office, I was involved in a big fight between another software engineer and the bus conductor on - how the ticket price was calculated? The software engineer did not know Kannada and the bus conductor could explain in the English. I served as the translator in that heated argument :)... here is the info how the ticket price is calculated.

        Note: The calculation is performed by the ticketing machine given to the bus conductor so the conductor cannot cheat you!

        BMTC divides the routes into stages. Following is the 'Fare Table' of BMTC Bus No 45. You can get the 'Fare Table' for your route from the conductor....Please Ask!













        FARE TABLE-010
        StageNameFare
        1KAMAKYA0.00
        2KATTRIGUPPE5.00
        3HOSAKERE HALLI9.00
        4BANK COLONY10.00
        5GANESH BHAVAN13.00
        6CHAMARAJPET15.00
        7GOODS ROAD16.00
        8KBS16.00


        Now the stage you climb the bus is the Stage 1 for you and of course the stage you get off is the last stage for you. Lets see the following examples of fare calculation with the previous assumption.

        Fare from

        • KAMAKYA to KBS = Stage 8 - Stage 0 = 8 Stages crossed = Rs 16
        • BANK COLONY to GOODS Road = Stage 7 - Stage 4 = 3 Stages Crossed = Rs 9
        • GOODS ROAD to KBS = Stage 8 - Stage 7 = 1 Stage crossed = Rs 5
        Algorithmically,


        List stageList=[KAMKYA...KBS]
        List fareList=[0..16]
        int start= stageList.indexOf[YOUR START STAGE]
        int end = stageList.indexOf[YOUR END STAGE]
        Fare= fareList[end-start]

        Hope the calculation is clear!

        Sunday, May 30, 2010

        Reading Java Concurrency

        The j.u.c package added to Java in 1.5 introduced me to the world of Concurrency research itself. Somehow i never thought of looking to this package beyond Executors class.

        Here is the study plan for that worked for me...
        1. Locks, Conditions And Fairness
        2. Understanding the Java Memory Model and its fix by JSR 133
        3. Happens-Before and volatile.
        4. LL/SC, CAS concepts
        5. Atomic package
        6. Concurrent Data Structures & Synchronizers
        7. Executors,Futures and other threading concepts.
        People & Forums:
        1. Articles by Brian Goetz, Doug Lea
        2. Java concurrency Interest group.

        Two useful books:
        1. Concurrent Programming In Java by Doug Lea.
        2. Java Concurrency in Practice By Brian Goetz