class AbstractPagingItemReader<T> extends AbstractItemCountingItemStreamItemReader<T>
		implements InitializingBean {

	protected Log logger = LogFactory.getLog(getClass());

	private volatile boolean initialized = false;

	private int pageSize = 10;

	private volatile int current = 0;

	private volatile int page = 0;

	protected volatile List<T> results;

	private final Lock lock = new ReentrantLock();

	public AbstractPagingItemReader() {
		setName(ClassUtils.getShortName(AbstractPagingItemReader.class));
	}

	/**
	 * The current page number.
	 * @return the current page
	 */
	public int getPage() {
		return page;
	}

	/**
	 * The page size configured for this reader.
	 * @return the page size
	 */
	public int getPageSize() {
		return pageSize;
	}

	/**
	 * The number of rows to retrieve at a time.
	 * @param pageSize the number of rows to fetch per page
	 */
	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}

	/**
	 * Check mandatory properties.
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
	 */
	@Override
	public void afterPropertiesSet() throws Exception {
		Assert.state(pageSize > 0, "pageSize must be greater than zero");
	}

	@Nullable
	@Override
	protected T doRead() throws Exception {

		this.lock.lock();
		try {

			if (results == null || current >= pageSize) {

				if (logger.isDebugEnabled()) {
					logger.debug("Reading page " + getPage());
				}

				doReadPage();
				page++;
				if (current >= pageSize) {
					current = 0;
				}

			}

			int next = current++;
			if (next < results.size()) {
				return results.get(next);
			}
			else {
				return null;
			}

		}
		finally {
			this.lock.unlock();
		}

	}

	abstract protected void doReadPage();

	@Override
	protected void doOpen() throws Exception {

		Assert.state(!initialized, "Cannot open an already opened ItemReader, call close first");
		initialized = true;

	}

	@Override
	protected void doClose() throws Exception {

		this.lock.lock();
		try {
			initialized = false;
			current = 0;
			page = 0;
			results = null;
		}
		finally {
			this.lock.unlock();
		}

	}

	@Override
	protected void jumpToItem(int itemIndex) throws Exception {<FILL_FUNCTION_BODY>}

}


		this.lock.lock();
		try {
			page = itemIndex / pageSize;
			current = itemIndex % pageSize;
		}
		finally {
			this.lock.unlock();
		}

		if (logger.isDebugEnabled()) {
			logger.debug("Jumping to page " + getPage() + " and index " + current);
		}

	
<methods>public non-sealed void <init>() ,public void close() throws org.springframework.batch.item.ItemStreamException,public int getCurrentItemCount() ,public boolean isSaveState() ,public void open(org.springframework.batch.item.ExecutionContext) throws org.springframework.batch.item.ItemStreamException,public T read() throws java.lang.Exception,public void setCurrentItemCount(int) ,public void setMaxItemCount(int) ,public void setSaveState(boolean) ,public void update(org.springframework.batch.item.ExecutionContext) throws org.springframework.batch.item.ItemStreamException<variables>private static final java.lang.String READ_COUNT,private static final java.lang.String READ_COUNT_MAX,private int currentItemCount,private int maxItemCount,private boolean saveState