1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.tomcat.util.collections;
18
19 /**
20 * This is intended as a (mostly) GC-free alternative to
21 * {@link java.util.concurrent.ConcurrentLinkedQueue} when the requirement is to
22 * create a pool of re-usable objects with no requirement to shrink the pool.
23 * The aim is to provide the bare minimum of required functionality as quickly
24 * as possible with minimum garbage.
25 *
26 * @param <T> The type of object managed by this stack
27 */
28 public class SynchronizedStack<T> {
29
30 public static final int DEFAULT_SIZE = 128;
31 private static final int DEFAULT_LIMIT = -1;
32
33 private int size;
34 private final int limit;
35
36 /*
37 * Points to the next available object in the stack
38 */
39 private int index = -1;
40
41 private Object[] stack;
42
43
44 public SynchronizedStack() {
45 this(DEFAULT_SIZE, DEFAULT_LIMIT);
46 }
47
48 public SynchronizedStack(int size, int limit) {
49 if (limit > -1 && size > limit) {
50 this.size = limit;
51 } else {
52 this.size = size;
53 }
54 this.limit = limit;
55 stack = new Object[size];
56 }
57
58
59 public synchronized boolean push(T obj) {
60 index++;
61 if (index == size) {
62 if (limit == -1 || size < limit) {
63 expand();
64 } else {
65 index--;
66 return false;
67 }
68 }
69 stack[index] = obj;
70 return true;
71 }
72
73 @SuppressWarnings("unchecked")
74 public synchronized T pop() {
75 if (index == -1) {
76 return null;
77 }
78 T result = (T) stack[index];
79 stack[index--] = null;
80 return result;
81 }
82
83 public synchronized void clear() {
84 if (index > -1) {
85 for (int i = 0; i < index + 1; i++) {
86 stack[i] = null;
87 }
88 }
89 index = -1;
90 }
91
92 private void expand() {
93 int newSize = size * 2;
94 if (limit != -1 && newSize > limit) {
95 newSize = limit;
96 }
97 Object[] newStack = new Object[newSize];
98 System.arraycopy(stack, 0, newStack, 0, size);
99 // This is the only point where garbage is created by throwing away the
100 // old array. Note it is only the array, not the contents, that becomes
101 // garbage.
102 stack = newStack;
103 size = newSize;
104 }
105 }
106