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