Bug 60417

Summary: autoSizeColumn(int i) swallows interrupted exception and resets interrupted flag
Product: POI Reporter: derblaueklabautermann
Component: XSSFAssignee: POI Developers List <dev>
Status: RESOLVED WONTFIX    
Severity: normal CC: derblaueklabautermann
Priority: P2    
Version: 3.16-dev   
Target Milestone: ---   
Hardware: PC   
OS: All   
Bug Depends on: 58896    
Bug Blocks:    

Description derblaueklabautermann 2016-11-25 00:16:24 UTC
Invoking 

org.apache.poi.ss.usermodel.Sheet.autoSizeColumn(int column)

in an interrupted thread (interrupted flag = "true") swallows the interrupted exception and resets the interrupted flag to "false". 
Therefore further checks whether the thread was interrupted or not will fail. This might cause some trouble.

This bug can be observed using both "HSSF" and "XSSF" workbooks (tested with the current beta-version (3.16-beta1-20161120)).

Code example to reproduce the bug:


import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;

public class MainClass {

	public static void main(String[] args) {

		Thread workerThread = new WorkerThread();
		workerThread.start();

		System.out.println("Main thread will go to sleep for 2 seconds...");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e) {
			Thread.currentThread().interrupt();
			System.out.println("Main thread interrupted while sleeping...");
		}
		System.out.println("Main thread woke up...");
		workerThread.interrupt();
		System.out.println("Interrupting worker thread...");
	}

	public static class WorkerThread extends Thread {

		private final Workbook workbook;

		public WorkerThread() {
			// this.workbook = new XSSFWorkbook();
			this.workbook = new HSSFWorkbook();
		}

		@Override
		public void run() {
			Sheet sheet = this.workbook.createSheet();

			for (int i = 0; i < 10; ++i) {
				sheet.createRow(i).createCell(0).setCellValue("Row " + i);
				System.out.println("\tWorkerThread - Before autosize: interrupted = " + this.isInterrupted());
				sheet.autoSizeColumn(0);
				System.out.println("\tWorkerThread - After autosize: interrupted = " + this.isInterrupted());
				++i;
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					this.interrupt();
					System.out.println("\tWorkerThread - Interrupted while sleeping...");
				}
			}
		}
	}
}


Output:

Main thread will go to sleep for 2 seconds...
	WorkerThread - Before autosize: interrupted = false
	WorkerThread - After autosize: interrupted = false
	WorkerThread - Before autosize: interrupted = false
	WorkerThread - After autosize: interrupted = false
Main thread woke up...
Interrupting worker thread...
	WorkerThread - Interrupted while sleeping...
	WorkerThread - Before autosize: interrupted = true
	WorkerThread - After autosize: interrupted = false
	WorkerThread - Before autosize: interrupted = false
	WorkerThread - After autosize: interrupted = false
	WorkerThread - Before autosize: interrupted = false
	WorkerThread - After autosize: interrupted = false

As one can clearly see, the interrupted flag is reset when autoSizeColumn(int i) is invoked.

The problem seems to occur somewhere deep in java.awt.font.TextLayout. Thus it's probably out of your scope to fix "the real bug".
However, I think it's still worth to have a look at it (and to be aware of this bug).
Comment 1 Javen O'Neal 2017-01-05 09:43:33 UTC
Auto-sizing columns is one of the slowest functions in POI relative to what users expect (auto-sizing is nearly instantaneous in Excel even for large workbooks). Bug 58896 and past discussion on the dev@ mailing list discuss ways to improve the speed of calculating the best-fit-width for a column.

Merged cells and rich text severely slow down the auto-size calculations (though our implementation of auto-sizing may not be much faster for plain text).

If the problem resides in java.awt.font.TextLayout, maybe one way we could side-step this problem is by rewriting auto-sizing without TextLayout.

POI does very little with threads or interruptions, so you're probably right that the interruption isn't originating from POI code. The only thing in POI that gets close to this is creating ThreadLocal variables in LocaleUtil and a few other locations. A quick grep didn't reveal an usages of Thread or interrupt outside of our test suite for unencrypted HSSF workbooks.
Comment 2 Dominik Stadler 2024-02-25 19:13:38 UTC
Tried to analyze this, but I fear there is nothing we can do about it. 

It seems to happen deep inside AWT text handling and it seems to be related to how much time elapsed, i.e. doing the calls quicker allows more iterations until the state is cleared. 

So I believe AWT is doing some "time-based cleanup" here, so likely not much we can do.