Jexl @parallel注解使用示例求助:并行执行未生效
@parallel Annotation: Working Examples & Troubleshooting Got it, let's dive into how to use JEXL's @parallel annotation properly—since the official docs are pretty light on examples, I'll walk you through working code snippets and explain why your attempts might have been running serially.
Basic Parallel Execution Example
First, let's start with a simple scenario: running multiple independent slow tasks in parallel. We'll use a utility class with simulated long-running methods, then call them via a JEXL script.
Step 1: Create a Thread-Safe Utility Class
Make sure any objects you use in parallel are thread-safe (since JEXL will execute the block across multiple threads):
public class SlowTasks { public long simulateDelay() { try { // Simulate 1 second of work Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } return System.currentTimeMillis(); } }
Step 2: Write the JEXL Script with @parallel
Wrap your independent operations in an @parallel block. These operations will run concurrently instead of sequentially:
// Inject our utility class instance into the context @parallel { task1End = slowTasks.simulateDelay(); task2End = slowTasks.simulateDelay(); task3End = slowTasks.simulateDelay(); } // Output completion times to verify parallel execution "Task 1 finished at: " + task1End + "\n" + "Task 2 finished at: " + task2End + "\n" + "Task 3 finished at: " + task3End
Step 3: Execute the Script in Java
Set up the JEXL engine, inject the utility class, and run the script:
import org.apache.commons.jexl3.*; public class JexlParallelDemo { public static void main(String[] args) { // Initialize JEXL engine JexlEngine jexl = new JexlBuilder().create(); // Create context and add our utility class JexlContext context = new MapContext(); context.set("slowTasks", new SlowTasks()); // Load and execute the script String scriptContent = "@parallel { task1End = slowTasks.simulateDelay(); task2End = slowTasks.simulateDelay(); task3End = slowTasks.simulateDelay(); } \"Task 1 finished at: \" + task1End + \"\\n\" + \"Task 2 finished at: \" + task2End + \"\\n\" + \"Task 3 finished at: \" + task3End"; JexlScript script = jexl.createScript(scriptContent); Object result = script.execute(context); System.out.println(result); } }
What to Expect
Without @parallel, this would take ~3 seconds (1s per task, sequential). With @parallel, it should finish in ~1 second—all three tasks run at the same time.
Common Pitfalls (Why Your Code Might Be Running Serially)
Version Compatibility: The
@parallelannotation was introduced in JEXL 3.1+. Make sure your dependency is up-to-date:<!-- Maven dependency example --> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-jexl3</artifactId> <version>3.3</version> <!-- Use the latest stable release --> </dependency>Variable Dependencies: If operations in your
@parallelblock depend on each other, JEXL will automatically run them sequentially to preserve correctness. For example:@parallel { a = 5 + 10; b = a * 2; // Depends on 'a'—this will run after 'a' is computed }Only independent operations (no shared variables between them) will be parallelized.
Non-Thread-Safe Context: If your JEXL context contains mutable, non-thread-safe objects, parallel execution can cause race conditions. Always ensure objects injected into the context are thread-safe or don't share mutable state across tasks.
Advanced Example: Parallel Collection Processing
You can also use @parallel with JEXL's foreach to process collection elements concurrently:
// Process a list of numbers to calculate their squares in parallel numbers = [1, 2, 3, 4, 5]; @parallel { squaredNumbers = numbers.foreach(n -> n * n); } // Output the result "Squared numbers: " + squaredNumbers
This will process each element in the list at the same time, which is much faster for large datasets.
内容的提问来源于stack exchange,提问作者Mikalai Ushanau

