When an int just won't do



  • import java.util.HashMap;
    import java.util.Map;

    public class Counters {
    public class Counter {
    private int counter;
    public Counter() { counter = 0; }
    public Counter(int seed) { counter = seed; }
    public int peek() { return counter; }
    public int next() { return ++counter; }
    public int prev() { return --counter; }
    public int [] getBatch(int numNumbersToGet) {
    int []result = new int[numNumbersToGet];
    for (int i=1; i<=numNumbersToGet; i++) {
    result[i-1] = next();
    }
    return result;
    }
    };

    private static Counters instance = null;
    private Map<String,Counter> counters = new HashMap<String,Counter>();

    private Counters() {}
    public static Counters getInstance() {
    if (instance == null) {
    synchronized (Counter.class) {
    if (instance == null) {
    instance = new Counters();
    }
    }
    }
    return instance;
    }

    public void createCounter(String name) {
    createCounter(name,0);
    }

    public void createCounter(String name, int seed) {
    assert(name != null);
    Counter c = counters.get(name);
    if (c == null) {
    c = new Counter(seed);
    counters.put(name,c);
    }
    }

    public Counter get(String name) {
    assert(name != null);
    Counter c = counters.get(name);
    if (c == null) {
    createCounter(name);
    c = counters.get(name);
    }
    return c;
    }
    }


  •  @snoofle said:

    getBatch

    This is supergood!

    I mean, what if I needed a big number like 38576482948726? It's not like you can just write that down immediately!




  • Considered Harmful

    Well, presumably they want to share these counters. Which is good because it's perfectly threadsafe. Yup. See, they used synchronized in getInstance. No concurrency issues here.



  •  Ok, so it's a very complicated way of doing a simple thing,but....

     If I actually needed a thread-safe, named counter in my code, what's a better alternative?



  • @lscharen said:

     Ok, so it's a very complicated way of doing a simple thing,but....

     If I actually needed a thread-safe, named counter in my code, what's a better alternative?

    Killing yourself?


  • Considered Harmful

    @lscharen said:

    thread-safe

    Take a closer look at createCounter() and get().



  • @lscharen said:

     Ok, so it's a very complicated way of doing a simple thing,but....

     If I actually needed a thread-safe, named counter in my code, what's a better alternative?

    Redis



  • @lscharen said:

     Ok, so it's a very complicated way of doing a simple thing,but....

     If I actually needed a thread-safe, named counter in my code, what's a better alternative?

    ConcurrentMap<String, AtomicLong>
    

    Oh God, I just noticed get() and createCounter(), as well as the double-checked-locking fail in getInstance()...



  • @drobnox said:

    @lscharen said:

     Ok, so it's a very complicated way of doing a simple thing,but....

     If I actually needed a thread-safe, named counter in my code, what's a better alternative?

    Redis

     

    For some bizarre reason, I would not consider replacing an integer counter with a server to be "better".

     



  • @hunter9000 said:

    @lscharen said:
    If I actually needed a thread-safe, named counter in my code, what's a better alternative?

    Killing yourself?

    In C#? Box it into an object and lock() it before you increment or read the value.

    In Java? ... yeah, "kill yourself" sounds right.



  • @blakeyrat said:

    @hunter9000 said:
    @lscharen said:
    If I actually needed a thread-safe, named counter in my code, what's a better alternative?

    Killing yourself?

    In C#? Box it into an object and lock() it before you increment or read the value.

    In Java? ... yeah, "kill yourself" sounds right.

    You can safely synchronize stuff in Java too - the tools are all built right in. Of course, not everyone knows when or how to use them...


  • Considered Harmful

    lock( foo ) is just sugar for


    Monitor.Enter( foo );
    try {
    // whatever
    } finally {
    Monitor.Exit( foo );
    }


    Point being that it's just a convenient way to make an API call, not really a language feature.



  • Ok. Did you have some kind of point you were making or...?


  • Considered Harmful

    Just that it's a capability made available to all languages, not just C#.

    What's that, the JVM doesn't like native API calls? Well, fuck.



  • @joe.edwards said:

    Just that it's a capability made available to all languages, not just C#.

    Well duh but how is that relevant to the discussion?

    ... eh nevermind. I have no idea how people's crazy's brains work.


  • ♿ (Parody)

    @blakeyrat said:

    @joe.edwards said:
    Just that it's a capability made available to all languages, not just C#.

    Well duh but how is that relevant to the discussion?

    ... eh nevermind. I have no idea how people's crazy's brains work why anyone needs to know how to do anything or would be interested in anything except exactly what I do.

    FTFY



  • @snoofle said:

    public Counter get(String name) {
    assert(name != null);
    Counter c = counters.get(name);
    if (c == null) {
    createCounter(name);
    c = counters.get(name);
    }
    return c;
    }
    My Java's a bit rusty, but is this not an endless loop?


  • @lolwtf said:

    @snoofle said:

    public Counter get(String name) {
    assert(name != null);
    Counter c = counters.get(name);
    if (c == null) {
    createCounter(name);
    c = counters.get(name);
    }
    return c;
    }
    My Java's a bit rusty, but is this not an endless loop?

    No. counters.get() is being called on a HashMap. The "public Counter get" method is different--it's not calling itself there.



  • The Go equivalent:

    var counters = map[string]int{}

    To increment a counter:

    counters["foo"]++

    To decrement a counter:

    counters["foo"]--

    To get the value of a counter, or 0 if it does not exist:

    foo = counters["foo"]

    It's every bit as threadsafe as the implementation in the OP. If you want thread safety, add a sync.Mutex. Or better yet, DROP THE FUCKING POINTLESS MAP.



  • @Ben L. said:

    To get the value of a counter, or 0 if it does not exist:

    foo = counters["foo"]

    Sooo.. how do you differentiate between a key that exists with a value of zero and a key that does not exist?



  • @morbiuswilters said:

    @Ben L. said:
    To get the value of a counter, or 0 if it does not exist:

    foo = counters["foo"]

    Sooo.. how do you differentiate between a key that exists with a value of zero and a key that does not exist?

    foo, exists := counters["foo"]

    Of course, you can name the variables whatever you want.



  • @blakeyrat said:

    @hunter9000 said:
    @lscharen said:
    If I actually needed a thread-safe, named counter in my code, what's a better alternative?

    Killing yourself?

    In C#? Box it into an object and lock() it before you increment or read the value.

    In Java? ... yeah, "kill yourself" sounds right.

    C# must have some equivalent of AtomicInteger or AtomicLong classes, surely?

    In Java these are thread safe objects provided in the standard concurrency utilities, which give you atomic methods like incrementAndGet(), compareAndSet(expected, update) and so on. That way you don't need the explicit locking code, which makes things like shared counters really simple.



  • CLASSES? For a measly atomic CAS instruction? Why the fuck would you box a fucking integer?



  • @grkvlt said:

    C# must have some equivalent of AtomicInteger or AtomicLong classes, surely?

    Yep... System.Threading.Interlocked has the equivalent.



  • @Ben L. said:

    CLASSES? For a measly atomic CAS instruction? Why the fuck would you box a fucking integer?

    Are you being retarded again? Java doesn't have global-level functions, so this shit has to be in a class. It's not even like it makes much of a difference at runtime, if any.



  • objectism, n.:

    Belief, that everything in a program must be an object. Fundamental form is especially widespread among Java programmers. Often combines with ↑patternism.

  • Discourse touched me in a no-no place

    @Bulb said:

    objectism, n.:

    Belief, that everything in a program must be an object. Fundamental form is especially widespread among Java programmers. Often combines with ↑patternism.
    There are languages that are even more strongly that way; Smalltalk is the classic example, but there are a few others (e.g., Ruby) that have everything being turtles all the way down too.

    But you're spot on with patternism; a lot of Java code is utterly infested with that (in the “Yaaargh! Kill it with fire and bug spray!!” sense).



  • @Bulb said:

    objectism, n.:
    Belief, that everything in a program must be an object. Fundamental form is especially widespread among Java programmers. Often combines with ↑patternism.
    There's nothing wrong with "everything is an object" per se. You're objection is probably against "functions can't be freestanding objects".



  •  the 'getBatch' starts at 1, regardless of the state of the 'counter'

    :)



  • @_leonardo_ said:

     the 'getBatch' starts at 1, regardless of the state of the 'counter'

    :)

    fail



  • @flabdablet said:

    @_leonardo_ said:

     the 'getBatch' starts at 1, regardless of the state of the 'counter'

    :)

    fail

    While that is wrong, it does combine the worst aspects of the 0-index vs 1-index debate with "fuck it, let's just do both things terribly".


Log in to reply