[java] Update AvoidSynchronizedAtMethodLevel message to mention ReentrantLock, new rule AvoidSynchronizedStatement (#5175)

Merge pull request #5175 from chonton:ReentrantLock
This commit is contained in:
Andreas Dangel
2024-08-29 12:50:13 +02:00
7 changed files with 126 additions and 8 deletions

View File

@ -1929,7 +1929,8 @@
"avatar_url": "https://avatars.githubusercontent.com/u/1444125?v=4", "avatar_url": "https://avatars.githubusercontent.com/u/1444125?v=4",
"profile": "http://www.linkedin.com/in/chonton", "profile": "http://www.linkedin.com/in/chonton",
"contributions": [ "contributions": [
"bug" "bug",
"code"
] ]
}, },
{ {

View File

@ -171,7 +171,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<td align="center" valign="top" width="14.28%"><a href="https://c-otto.de/"><img src="https://avatars.githubusercontent.com/u/344948?v=4?s=100" width="100px;" alt="Carsten Otto"/><br /><sub><b>Carsten Otto</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3AC-Otto" title="Bug reports">🐛</a></td> <td align="center" valign="top" width="14.28%"><a href="https://c-otto.de/"><img src="https://avatars.githubusercontent.com/u/344948?v=4?s=100" width="100px;" alt="Carsten Otto"/><br /><sub><b>Carsten Otto</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3AC-Otto" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/HoushCE29"><img src="https://avatars.githubusercontent.com/u/22387324?v=4?s=100" width="100px;" alt="Charlie Housh"/><br /><sub><b>Charlie Housh</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3AHoushCE29" title="Bug reports">🐛</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/HoushCE29"><img src="https://avatars.githubusercontent.com/u/22387324?v=4?s=100" width="100px;" alt="Charlie Housh"/><br /><sub><b>Charlie Housh</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3AHoushCE29" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/ChuckJonas"><img src="https://avatars.githubusercontent.com/u/5217568?v=4?s=100" width="100px;" alt="Charlie Jonas"/><br /><sub><b>Charlie Jonas</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3AChuckJonas" title="Bug reports">🐛</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/ChuckJonas"><img src="https://avatars.githubusercontent.com/u/5217568?v=4?s=100" width="100px;" alt="Charlie Jonas"/><br /><sub><b>Charlie Jonas</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3AChuckJonas" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="http://www.linkedin.com/in/chonton"><img src="https://avatars.githubusercontent.com/u/1444125?v=4?s=100" width="100px;" alt="Chas Honton"/><br /><sub><b>Chas Honton</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Achonton" title="Bug reports">🐛</a></td> <td align="center" valign="top" width="14.28%"><a href="http://www.linkedin.com/in/chonton"><img src="https://avatars.githubusercontent.com/u/1444125?v=4?s=100" width="100px;" alt="Chas Honton"/><br /><sub><b>Chas Honton</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Achonton" title="Bug reports">🐛</a> <a href="https://github.com/pmd/pmd/commits?author=chonton" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/willamette"><img src="https://avatars.githubusercontent.com/u/1435016?v=4?s=100" width="100px;" alt="Chen Yang"/><br /><sub><b>Chen Yang</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Awillamette" title="Bug reports">🐛</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/willamette"><img src="https://avatars.githubusercontent.com/u/1435016?v=4?s=100" width="100px;" alt="Chen Yang"/><br /><sub><b>Chen Yang</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Awillamette" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/bashagithub"><img src="https://avatars.githubusercontent.com/u/25314601?v=4?s=100" width="100px;" alt="Chotu"/><br /><sub><b>Chotu</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Abashagithub" title="Bug reports">🐛</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/bashagithub"><img src="https://avatars.githubusercontent.com/u/25314601?v=4?s=100" width="100px;" alt="Chotu"/><br /><sub><b>Chotu</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Abashagithub" title="Bug reports">🐛</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/tophersmith"><img src="https://avatars.githubusercontent.com/u/812876?v=4?s=100" width="100px;" alt="Chris Smith"/><br /><sub><b>Chris Smith</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Atophersmith" title="Bug reports">🐛</a></td> <td align="center" valign="top" width="14.28%"><a href="https://github.com/tophersmith"><img src="https://avatars.githubusercontent.com/u/812876?v=4?s=100" width="100px;" alt="Chris Smith"/><br /><sub><b>Chris Smith</b></sub></a><br /><a href="https://github.com/pmd/pmd/issues?q=author%3Atophersmith" title="Bug reports">🐛</a></td>

View File

@ -14,6 +14,11 @@ This is a {{ site.pmd.release_type }} release.
### 🚀 New and noteworthy ### 🚀 New and noteworthy
### 🌟 New and changed rules
#### New Rules
* The new Java rule {%rule java/multithreading/AvoidSynchronizedStatement %} finds synchronization blocks that
could cause performance issues with virtual threads due to pinning.
### 🐛 Fixed Issues ### 🐛 Fixed Issues
* apex-performance * apex-performance
* [#5139](https://github.com/pmd/pmd/issues/5139): \[apex] OperationWithHighCostInLoop: false negative for triggers * [#5139](https://github.com/pmd/pmd/issues/5139): \[apex] OperationWithHighCostInLoop: false negative for triggers
@ -26,6 +31,8 @@ This is a {{ site.pmd.release_type }} release.
* [#5151](https://github.com/pmd/pmd/issues/5151): \[java] GuardLogStatement: Should not need to guard parameterized log messages where the replacement arg is a constant from another class * [#5151](https://github.com/pmd/pmd/issues/5151): \[java] GuardLogStatement: Should not need to guard parameterized log messages where the replacement arg is a constant from another class
* [#5152](https://github.com/pmd/pmd/issues/5152): \[java] GuardLogStatement: Should not need to guard parameterized log messages where the replacement arg is "this" * [#5152](https://github.com/pmd/pmd/issues/5152): \[java] GuardLogStatement: Should not need to guard parameterized log messages where the replacement arg is "this"
* [#5153](https://github.com/pmd/pmd/issues/5153): \[java] GuardLogStatement: Should not need to guard parameterized log messages where the replacement arg is an array element * [#5153](https://github.com/pmd/pmd/issues/5153): \[java] GuardLogStatement: Should not need to guard parameterized log messages where the replacement arg is an array element
* java-multithreading
* [#5175](https://github.com/pmd/pmd/issues/5175): \[java] Update AvoidSynchronizedAtMethodLevel message to mention ReentrantLock, new rule AvoidSynchronizedStatement
* plsql * plsql
* [#5125](https://github.com/pmd/pmd/pull/5125): \[plsql] Improve merge statement (order of merge insert/update flexible, allow prefixes in column names) * [#5125](https://github.com/pmd/pmd/pull/5125): \[plsql] Improve merge statement (order of merge insert/update flexible, allow prefixes in column names)
* plsql-bestpractices * plsql-bestpractices
@ -48,6 +55,7 @@ This is a {{ site.pmd.release_type }} release.
### ✨ External Contributions ### ✨ External Contributions
* [#5125](https://github.com/pmd/pmd/pull/5125): \[plsql] Improve merge statement (order of merge insert/update flexible, allow prefixes in column names) - [Arjen Duursma](https://github.com/duursma) (@duursma) * [#5125](https://github.com/pmd/pmd/pull/5125): \[plsql] Improve merge statement (order of merge insert/update flexible, allow prefixes in column names) - [Arjen Duursma](https://github.com/duursma) (@duursma)
* [#5175](https://github.com/pmd/pmd/pull/5175): \[java] Update AvoidSynchronizedAtMethodLevel message to mention ReentrantLock, new rule AvoidSynchronizedStatement - [Chas Honton](https://github.com/chonton) (@chonton)
{% endtocmaker %} {% endtocmaker %}

View File

@ -12,13 +12,13 @@ Rules that flag issues when dealing with multiple threads of execution.
<rule name="AvoidSynchronizedAtMethodLevel" <rule name="AvoidSynchronizedAtMethodLevel"
language="java" language="java"
since="3.0" since="3.0"
message="Use block level rather than method level synchronization" message="Use block level locking rather than method level synchronization"
class="net.sourceforge.pmd.lang.rule.xpath.XPathRule" class="net.sourceforge.pmd.lang.rule.xpath.XPathRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_multithreading.html#avoidsynchronizedatmethodlevel"> externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_multithreading.html#avoidsynchronizedatmethodlevel">
<description> <description>
Method-level synchronization can cause problems when new code is added to the method. Method-level synchronization will pin virtual threads and can cause performance problems. Additionally, it can cause
Block-level synchronization helps to ensure that only the code that needs synchronization problems when new code is added to the method. Block-level ReentrantLock helps to ensure that only the code that
gets it. needs mutual exclusion will be locked.
</description> </description>
<priority>3</priority> <priority>3</priority>
<properties> <properties>
@ -41,13 +41,18 @@ public class Foo {
// ... // ...
} }
// Prefer this: // Prefer this:
Lock instanceLock = new ReentrantLock();
void bar() { void bar() {
// code, that doesn't need synchronization // code, that doesn't need synchronization
// ... // ...
synchronized(this) { try {
instanceLock.lock(); // or instanceLock.tryLock(long time, TimeUnit unit)
if (!sharedData.has("bar")) { if (!sharedData.has("bar")) {
sharedData.add("bar"); sharedData.add("bar");
} }
} finally {
instanceLock.unlock();
} }
// more code, that doesn't need synchronization // more code, that doesn't need synchronization
// ... // ...
@ -58,11 +63,16 @@ public class Foo {
} }
// Prefer this: // Prefer this:
private static Lock CLASS_LOCK = new ReentrantLock();
static void barStatic() { static void barStatic() {
// code, that doesn't need synchronization // code, that doesn't need synchronization
// ... // ...
synchronized(Foo.class) { try {
CLS_LOCK.lock();
// code, that requires synchronization // code, that requires synchronization
} finally {
CLS_LOCK.unlock();
} }
// more code, that doesn't need synchronization // more code, that doesn't need synchronization
// ... // ...
@ -72,6 +82,50 @@ public class Foo {
</example> </example>
</rule> </rule>
<rule name="AvoidSynchronizedStatement"
language="java"
since="7.5.0"
message="Use ReentrantLock rather than synchronization"
class="net.sourceforge.pmd.lang.rule.xpath.XPathRule"
externalInfoUrl="${pmd.website.baseurl}/pmd_rules_java_multithreading.html#avoidsynchronizedstatement">
<description>
Synchronization will pin virtual threads and can cause performance problems.
</description>
<priority>3</priority>
<properties>
<property name="xpath">
<value>//SynchronizedStatement</value>
</property>
</properties>
<example>
<![CDATA[
public class Foo {
// Try to avoid this:
void foo() {
// code that doesn't need mutual exclusion
synchronized(this) {
// code that requires mutual exclusion
}
// more code that doesn't need mutual exclusion
}
// Prefer this:
Lock instanceLock = new ReentrantLock();
void foo() {
// code that doesn't need mutual exclusion
try {
instanceLock.lock(); // or instanceLock.tryLock(long time, TimeUnit unit)
// code that requires mutual exclusion
} finally {
instanceLock.unlock();
}
// more code that doesn't need mutual exclusion
}
}
]]>
</example>
</rule>
<rule name="AvoidThreadGroup" <rule name="AvoidThreadGroup"
language="java" language="java"
since="3.6" since="3.6"

View File

@ -279,6 +279,7 @@
<!-- <rule ref="category/java/multithreading.xml/AvoidSynchronizedAtMethodLevel" /> --> <!-- <rule ref="category/java/multithreading.xml/AvoidSynchronizedAtMethodLevel" /> -->
<!-- <rule ref="category/java/multithreading.xml/AvoidSynchronizedStatement" /> -->
<rule ref="category/java/multithreading.xml/AvoidThreadGroup"/> <rule ref="category/java/multithreading.xml/AvoidThreadGroup"/>
<rule ref="category/java/multithreading.xml/AvoidUsingVolatile"/> <rule ref="category/java/multithreading.xml/AvoidUsingVolatile"/>
<!-- <rule ref="category/java/multithreading.xml/DoNotUseThreads" /> --> <!-- <rule ref="category/java/multithreading.xml/DoNotUseThreads" /> -->

View File

@ -0,0 +1,11 @@
/**
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
package net.sourceforge.pmd.lang.java.rule.multithreading;
import net.sourceforge.pmd.test.PmdRuleTst;
class AvoidSynchronizedStatementTest extends PmdRuleTst {
// no additional unit tests
}

View File

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8"?>
<test-data
xmlns="http://pmd.sourceforge.net/rule-tests"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sourceforge.net/rule-tests http://pmd.sourceforge.net/rule-tests_1_0_0.xsd">
<test-code>
<description>Synchronized block in instance method</description>
<expected-problems>1</expected-problems>
<code><![CDATA[
public class Foo {
void foo () {
synchronized(mutex) {}
}
}
]]></code>
</test-code>
<test-code>
<description>Synchronized block in static methods</description>
<expected-problems>1</expected-problems>
<code><![CDATA[
public class Test {
public static void foo() {
synchronized(Test.class) {
// only a block is synchronized on Test.class
}
}
}
]]></code>
</test-code>
<test-code>
<description>synchronized methods are not flagged - we have a separate rule AvoidSynchronizedAtMethodLevel for that</description>
<expected-problems>0</expected-problems>
<code><![CDATA[
public class Test {
public synchronized void foo() {}
public static synchronized void fooStatic() {}
}
]]></code>
</test-code>
</test-data>