盡管函式從 Java 8 開始就出現在 Java 中,但我最近才開始使用它們。因此,這個問題可能聽起來有點陳舊,請原諒。
首先,我說的是完全符合函式式編程定義的純函式:確定性和不可變的。
比如說,我經常需要在一個字串前面加上另一個靜態值。像下面的例子:
private static Function<String, String> fnPrependString = (s) -> {
return "prefix_" s;
};
在舊方法中,Helper 類及其靜態方法本來可以為我完成這項作業。
現在的問題是,我是否可以創建這些函式一次并像輔助方法一樣重用它們。
一種威脅是執行緒安全。我使用一個簡單的測驗來檢查這個 JUnit 測驗:
package com.me.expt.lt.test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.function.Consumer;
import java.util.function.Function;
import org.junit.jupiter.api.Test;
import com.vmlens.api.AllInterleavings;
public class TestFunctionThreadSafety {
private static Function<String, String> fnPrepend = (s) -> {
System.out.println(s);
return new StringBuffer("prefix_").append(s).toString();
};
@Test
public void testThreadSafety() throws InterruptedException {
try (AllInterleavings allInterleavings = new AllInterleavings(
TestFunctionThreadSafety.class.getCanonicalName());) {
ConcurrentMap<String, Integer> resultMap = new ConcurrentHashMap<String, Integer>();
while (allInterleavings.hasNext()) {
int runSize = 5;
Thread[] threads = new Thread[runSize];
ThreadToRun[] ttrArray = new ThreadToRun[runSize];
StringBuffer sb = new StringBuffer("0");
for (int i = 0; i < runSize; i ) {
if (i > 0)
sb.append(i);
ttrArray[i] = new ThreadToRun();
ttrArray[i].setS(sb.toString());
threads[i] = new Thread(ttrArray[i]);
}
for (int j = 0; j < runSize; j ) {
threads[j].start();
}
for (int j = 0; j < runSize; j ) {
threads[j].join();
}
System.out.println(resultMap);
StringBuffer newBuffer = new StringBuffer("0");
for (int j = 0; j < runSize; j ) {
if(j>0)
newBuffer.append(j);
assertEquals("prefix_" newBuffer, ttrArray[j].getResult(), j " fails");
}
}
}
}
private static class ThreadToRun implements Runnable {
private String s;
private String result;
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
public String getResult() {
return result;
}
@Override
public void run() {
this.result = fnPrepend.apply(s);
}
}
}
I am using vmlens. I can tune my test by changing the runSize variable by as good a number as I choose so that the randomness can be checked. The objective is to see if these multiple threads using the same function mix up their inputs because of concurrent access. The test did not return any negative results. Please also do comment on whether the test meets the goals.
I also tried to understand the internal VM end of how lambdas are executed from here. Even as I look for somewhat simpler articles that I can understand these details faster, I did not find anything that says "Lambdas will have thread safety issues".
Assuming the test case meets my goal, the consequential questions are:
Can we replace the static helper classes with function variables immutable and deterministic functions like
fnPrepend? The objective is to simply provide more readable code and also of course to move away from the "not so Object oriented" criticism about static methods.Is there is a source of simpler explanation to how Lambdas work inside the vm?
Can the results above with a
Function<InputType, ResultType>be applied to aSupplier<SuppliedType>and aConsumer<ConsumedType>also?
Some more familiarity with functions and the bytecode will possibly help me answer these questions. But a knowledge exchange forum like this may get me an answer faster and the questions may trigger more ideas for the readers.
Thanks in advance. Rahul
uj5u.com熱心網友回復:
作為用戶,我真的不認為您需要花費如此大的精力來證明 JVM 對 lambda 的保證。基本上,它們就像 JVM 的任何其他方法一樣,沒有特殊的記憶體或可見性影響 :)
這是一個較短的函式定義:
private static Function<String, String> fnPrepend = s -> "prefix_" s;
this.result = fnPrepend.apply(s);
...但不要僅僅為了這樣而使用 lambda - 這只是相同行為的額外開銷。假設真實用例對 a 有需求Function,我們可以使用 方法參考來呼叫靜態方法。這讓你兩全其美:
// Available as normal static method
public static String fnPrepend(String s) {
return "prefix_" s;
}
// Takes a generic Function
public static void someMethod(UnaryOperator<String> prefixer) {
...
}
// Coerce the static method to a function
someMethod(Util::fnPrepend);
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/354217.html
標籤:java multithreading function lambda thread-safety
