10

I have a large codebase (written by me) that uses the Stack data structure. This was used for convenience and I am using it as Stack sometimes or Vector/List some other times.

After a performance review however it was decided that we do not want to pay extra for the synchronization safety. I need now to replace this structure with a non-synchronized one (and it is mentioned a lot of times in the code).

I was happy to discover that Apache collections includes an ArrayStack which is exactly what I want (same as Java stack but non-synchronized). However this does NOT have generics as modern Java 5 code (which is what I use). And I am not going to convert my code to look like Java 1.4

So is there any other Java 5 compliant drop-in replacement for Java Stack or do I need to write my own?

Update:

I used LinkedList with tuned "pop"/"push" methods.

kazanaki
  • 7,988
  • 8
  • 52
  • 79
  • Like Jon Skeet said, ArrayDeque is the way to go. BTW, ArrayStack is broken in the same sense as Stack, as ArrayStack inherits from ArrayList, which is a good example of a bad use of inheritance ;-). – helpermethod Feb 16 '11 at 09:52
  • By the way, if you're using a modern HotSpot JVM, there is a good chance that it has optimized away the locks for you. For example, it has already made the transition from `StringBuffer` (synchronized) to `StringBuilder` (non-synchronized) largely unnecessary (although it still has its place). – Adam Paynter Feb 16 '11 at 09:53
  • @Adam Yes I know, but try explaining that to the client! – kazanaki Feb 16 '11 at 10:06
  • 1
    @kazanaki: Fair enough. By the way, who conducted this "performance review" that you must now adhere to? A consulting firm? Do you know as to whether or not they *measured* the performance of the existing application to guide their recommendations? – Adam Paynter Feb 16 '11 at 10:15
  • @Adam The review was performed by the client. Don't ask... – kazanaki Feb 16 '11 at 11:14
  • @kazanaki: You have my sympathy. :) – Adam Paynter Feb 16 '11 at 11:48
  • FWIW: Sonar/Findbugs complains about unnecessary synchronization in these classes, too. – Dale Wilson Nov 08 '17 at 20:35

2 Answers2

10

When you say "Java 5 compliant" - ArrayDeque<T> didn't arrive until Java 6, but sounds like what you're after (using the Deque<T> interface where appropriate, of course). You can use it as a stack when you want to, or a queue where that's more appropriate... just call the appropriate methods, basically.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 4
    In Java 5.0, you can use `LinkedList` with `add(0, E)` for push and `remove(0)` for pop. – Peter Lawrey Feb 16 '11 at 09:59
  • @Peter: I agree. It's just a shame to rely on a concrete type. :( – Adam Paynter Feb 16 '11 at 10:01
  • @Peter I will probably do what you say. If you want, post your comment as an answer so I can accept it! Otherwise Sir Jon Skeet gets all the glory! – kazanaki Feb 16 '11 at 10:08
  • @Peter: I considered mentioning LinkedList, but suspected that the OP wanted the (partial) cache coherency of an array-based solution. But yes, LinkedList will work too. – Jon Skeet Feb 16 '11 at 10:16
  • @kazanaki: Does this mean that you're stuck with *precisely* Java 5 and not Java 6? It would be a shame to go through the effort of replacing all your `Stack`s with another concrete class like `LinkedList`. Coding to an interface would be nicer, in my opinion. – Adam Paynter Feb 16 '11 at 10:17
  • 3
    @kazanaki, You can use List as the interface as this will work with any list. However for ArrayList to work efficiently you have to add/remove from the end. (This is faster than using LinkedList but uglier) `add(e)` for push and `remove(list.size()-1)` for pop. – Peter Lawrey Feb 16 '11 at 10:46
  • @Adam Paynter: LinkedList implements both Queue and Deque. No need to rely on a concrete type. – barjak Feb 16 '11 at 13:08
  • @barjak: That is correct *in Java 6*. In Java 5, it did not implement `Deque`. That is why I asked kazanaki if he was strictly limited to Java 5. – Adam Paynter Feb 16 '11 at 13:41
0

In your special case (and actually only in such a case), I'd simply copy and paste the Stack class from an open source Java SE implementation into your own package, and remove all synchronized keywords. You may want to add extends java.util.Stack. Now you'll only have to change the import declarations in your code.

I do realize, that typically it's not a good idea to copy code, but here's why this doesn't apply to this case:

  • If the the pop() and push() semantics of a Stack fit well for the current code, then this doesn't change just because of performance considerations. The semantics of a deque or linked list are different (they allow to add/remove from both sides).
  • The synchronization overhead of java.util.Stack cannot be removed by another technique like subclassing (calling super methods) or delegation.
  • It's better to copy well tested code (as far as the license allows it), than to rewrite from scratch.

In general, it would be a lot better to use java.util.Stack as if it were an interface, and not to use new Stack() in the code, but to instantiate it by using factories.

Chris Lercher
  • 37,264
  • 20
  • 99
  • 131
  • 1
    copyright must be respected. in general it's a bad idea to copy code, especially from Oracle:) And it's a "stack", anyone should be able to write one from scratch. – irreputable Feb 16 '11 at 11:18
  • @irreputable: That's why I said explicitly "from an **open source** Java SE implementation" (and I mean e.g. Apache Harmony). Of course, it's still necessary to respect the license, but if you do, you may copy it. – Chris Lercher Feb 16 '11 at 11:25