/* * Copyright 2014 The Netty Project * * The Netty Project licenses this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package io.netty.util; import org.junit.Test; import java.util.Random; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; public class RecyclerTest { @Test(expected = IllegalStateException.class) public void testMultipleRecycle() { RecyclableObject object = RecyclableObject.newInstance(); object.recycle(); object.recycle(); } @Test public void testRecycle() { RecyclableObject object = RecyclableObject.newInstance(); object.recycle(); RecyclableObject object2 = RecyclableObject.newInstance(); assertSame(object, object2); object2.recycle(); } static final class RecyclableObject { private static final Recycler<RecyclableObject> RECYCLER = new Recycler<RecyclableObject>() { @Override protected RecyclableObject newObject(Handle handle) { return new RecyclableObject(handle); } }; private final Recycler.Handle handle; private RecyclableObject(Recycler.Handle handle) { this.handle = handle; } public static RecyclableObject newInstance() { return RECYCLER.get(); } public void recycle() { RECYCLER.recycle(this, handle); } } /** * Test to make sure bug #2848 never happens again * https://github.com/netty/netty/issues/2848 */ @Test public void testMaxCapacity() { testMaxCapacity(300); Random rand = new Random(); for (int i = 0; i < 50; i++) { testMaxCapacity(rand.nextInt(1000) + 256); // 256 - 1256 } } void testMaxCapacity(int maxCapacity) { Recycler<HandledObject> recycler = new Recycler<HandledObject>(maxCapacity) { @Override protected HandledObject newObject( Recycler.Handle handle) { return new HandledObject(handle); } }; HandledObject[] objects = new HandledObject[maxCapacity * 3]; for (int i = 0; i < objects.length; i++) { objects[i] = recycler.get(); } for (int i = 0; i < objects.length; i++) { recycler.recycle(objects[i], objects[i].handle); objects[i] = null; } assertEquals(maxCapacity, recycler.threadLocalCapacity()); } @Test public void testRecycleAtDifferentThread() throws Exception { final Recycler<HandledObject> recycler = new Recycler<HandledObject>(256) { @Override protected HandledObject newObject(Recycler.Handle handle) { return new HandledObject(handle); } }; final HandledObject o = recycler.get(); final Thread thread = new Thread() { @Override public void run() { recycler.recycle(o, o.handle); } }; thread.start(); thread.join(); assertThat(recycler.get(), is(sameInstance(o))); } @Test public void testMaxCapacityWithRecycleAtDifferentThread() throws Exception { final int maxCapacity = 4; // Choose the number smaller than WeakOrderQueue.LINK_CAPACITY final Recycler<HandledObject> recycler = new Recycler<HandledObject>(maxCapacity) { @Override protected HandledObject newObject(Recycler.Handle handle) { return new HandledObject(handle); } }; // Borrow 2 * maxCapacity objects. // Return the half from the same thread. // Return the other half from the different thread. final HandledObject[] array = new HandledObject[maxCapacity * 3]; for (int i = 0; i < array.length; i ++) { array[i] = recycler.get(); } for (int i = 0; i < maxCapacity; i ++) { recycler.recycle(array[i], array[i].handle); } final Thread thread = new Thread() { @Override public void run() { for (int i = maxCapacity; i < array.length; i ++) { recycler.recycle(array[i], array[i].handle); } } }; thread.start(); thread.join(); assertThat(recycler.threadLocalCapacity(), is(maxCapacity)); assertThat(recycler.threadLocalSize(), is(maxCapacity)); for (int i = 0; i < array.length; i ++) { recycler.get(); } assertThat(recycler.threadLocalCapacity(), is(maxCapacity)); assertThat(recycler.threadLocalSize(), is(0)); } static final class HandledObject { Recycler.Handle handle; HandledObject(Recycler.Handle handle) { this.handle = handle; } } }