This is an automated email from the ASF dual-hosted git repository.
ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-csv.git
The following commit(s) were added to refs/heads/master by this push:
new 241a9e4e CSVPrinter now uses an internal lock instead of synchronized
methods
241a9e4e is described below
commit 241a9e4e3bf2f3e7a8b024e432af4b02a76001b8
Author: Gary Gregory <[email protected]>
AuthorDate: Wed May 7 07:23:45 2025 -0400
CSVPrinter now uses an internal lock instead of synchronized methods
---
src/changes/changes.xml | 1 +
.../java/org/apache/commons/csv/CSVPrinter.java | 112 +++++++++++++--------
2 files changed, 72 insertions(+), 41 deletions(-)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index a2d02ac4..752037d3 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -43,6 +43,7 @@
<release version="1.14.1" date="YYYY-MM-DD" description="This is a feature
and maintenance release. Java 8 or later is required.">
<!-- FIX -->
<action type="fix" issue="CSV-318" dev="ggregory" due-to="Joseph
Shraibman, Gary Gregory">CSVPrinter.printRecord(Stream) hangs if given a
parallel stream.</action>
+ <action type="fix" issue="CSV-318" dev="ggregory" due-to="Joseph
Shraibman, Gary Gregory">CSVPrinter now uses an internal lock instead of
synchronized methods.</action>
<!-- ADD -->
<!-- UPDATE -->
<action type="update" dev="ggregory" due-to="Gary Gregory">Bump
commons-io:commons-io from 2.18.0 to 2.19.0.</action>
diff --git a/src/main/java/org/apache/commons/csv/CSVPrinter.java
b/src/main/java/org/apache/commons/csv/CSVPrinter.java
index a55faae2..dd1df081 100644
--- a/src/main/java/org/apache/commons/csv/CSVPrinter.java
+++ b/src/main/java/org/apache/commons/csv/CSVPrinter.java
@@ -151,9 +151,14 @@ public final class CSVPrinter implements Flushable,
Closeable {
* @throws IOException
* If an I/O error occurs
*/
- private synchronized void endOfRecord() throws IOException {
- println();
- recordCount++;
+ private void endOfRecord() throws IOException {
+ lock.lock();
+ try {
+ println();
+ recordCount++;
+ } finally {
+ lock.unlock();
+ }
}
/**
@@ -196,9 +201,14 @@ public final class CSVPrinter implements Flushable,
Closeable {
* @throws IOException
* If an I/O error occurs
*/
- public synchronized void print(final Object value) throws IOException {
- format.print(value, appendable, newRecord);
- newRecord = false;
+ public void print(final Object value) throws IOException {
+ lock.lock();
+ try {
+ format.print(value, appendable, newRecord);
+ newRecord = false;
+ } finally {
+ lock.unlock();
+ }
}
/**
@@ -222,34 +232,39 @@ public final class CSVPrinter implements Flushable,
Closeable {
* @throws IOException
* If an I/O error occurs
*/
- public synchronized void printComment(final String comment) throws
IOException {
- if (comment == null || !format.isCommentMarkerSet()) {
- return;
- }
- if (!newRecord) {
- println();
- }
- appendable.append(format.getCommentMarker().charValue()); // Explicit
(un)boxing is intentional
- appendable.append(SP);
- for (int i = 0; i < comment.length(); i++) {
- final char c = comment.charAt(i);
- switch (c) {
- case CR:
- if (i + 1 < comment.length() && comment.charAt(i + 1) == LF) {
- i++;
- }
- // falls-through: break intentionally excluded.
- case LF:
+ public void printComment(final String comment) throws IOException {
+ lock.lock();
+ try {
+ if (comment == null || !format.isCommentMarkerSet()) {
+ return;
+ }
+ if (!newRecord) {
println();
- appendable.append(format.getCommentMarker().charValue()); //
Explicit (un)boxing is intentional
- appendable.append(SP);
- break;
- default:
- appendable.append(c);
- break;
}
+ appendable.append(format.getCommentMarker().charValue()); //
Explicit (un)boxing is intentional
+ appendable.append(SP);
+ for (int i = 0; i < comment.length(); i++) {
+ final char c = comment.charAt(i);
+ switch (c) {
+ case CR:
+ if (i + 1 < comment.length() && comment.charAt(i + 1) ==
LF) {
+ i++;
+ }
+ // falls-through: break intentionally excluded.
+ case LF:
+ println();
+ appendable.append(format.getCommentMarker().charValue());
// Explicit (un)boxing is intentional
+ appendable.append(SP);
+ break;
+ default:
+ appendable.append(c);
+ break;
+ }
+ }
+ println();
+ } finally {
+ lock.unlock();
}
- println();
}
/**
@@ -260,11 +275,16 @@ public final class CSVPrinter implements Flushable,
Closeable {
* @throws SQLException If a database access error occurs or this method
is called on a closed result set.
* @since 1.9.0
*/
- public synchronized void printHeaders(final ResultSet resultSet) throws
IOException, SQLException {
- try (IOStream<String> stream =
IOStream.of(format.builder().setHeader(resultSet).get().getHeader())) {
- stream.forEachOrdered(this::print);
+ public void printHeaders(final ResultSet resultSet) throws IOException,
SQLException {
+ lock.lock();
+ try {
+ try (IOStream<String> stream =
IOStream.of(format.builder().setHeader(resultSet).get().getHeader())) {
+ stream.forEachOrdered(this::print);
+ }
+ println();
+ } finally {
+ lock.unlock();
}
- println();
}
/**
@@ -273,9 +293,14 @@ public final class CSVPrinter implements Flushable,
Closeable {
* @throws IOException
* If an I/O error occurs
*/
- public synchronized void println() throws IOException {
- format.println(appendable);
- newRecord = true;
+ public void println() throws IOException {
+ lock.lock();
+ try {
+ format.println(appendable);
+ newRecord = true;
+ } finally {
+ lock.unlock();
+ }
}
/**
@@ -292,9 +317,14 @@ public final class CSVPrinter implements Flushable,
Closeable {
* If an I/O error occurs
*/
@SuppressWarnings("resource")
- public synchronized void printRecord(final Iterable<?> values) throws
IOException {
- IOStream.of(values).forEachOrdered(this::print);
- endOfRecord();
+ public void printRecord(final Iterable<?> values) throws IOException {
+ lock.lock();
+ try {
+ IOStream.of(values).forEachOrdered(this::print);
+ endOfRecord();
+ } finally {
+ lock.unlock();
+ }
}
/**