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 <garydgreg...@gmail.com>
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();
+        }
     }
 
     /**

Reply via email to