问题陈述:
我在运行以下多线程程序时遇到问题。该程序生成大量线程(10,000 个)来处理相同的字节数组值。在 CPU 使用率较高和应用内存限制时(例如,设置 -Xms32m -Xmx32m),此问题会变得更加频繁。
方法 byteArrayToInt 应该将字节数组的特定段转换为整数。然而,它会间歇性地产生不正确的值。 liVersion 的预期值为 1,但改为观察随机值。即使程序以足够的内存和较少的线程数(甚至单线程)执行,也会出现此问题,但频率明显降低。
pTestData 的第 2 个到第 4 个值([1, 0])的整数转换应该为 1,但它在输出中间歇性地给出随机值。
环境:
操作系统:Windows 10
Java版本:采用OpenJDK 17.0.10
代码片段:
import java.util.Arrays;
public class TestMain
{
private static int miParallelThreadCount = 10000;
private static long mlExecutionIntervalInMillis=100;
public static void main(String[] args)
{
System.out.println("Startin tornado at interval: " + mlExecutionIntervalInMillis + " with parallel threads: " + miParallelThreadCount);
while(true)
{
//Runs the test code to reproduce the issue
runTornado();
try
{
Thread.sleep(mlExecutionIntervalInMillis);
} catch (Throwable lThrowable)
{
System.out.println("Task failed due to: " + lThrowable.getLocalizedMessage());
lThrowable.printStackTrace();
}
}
}
private static void runTornado()
{
//Test byte array
byte[] data = new byte[]
{ 65, 50, 1, 0, 1, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 16, 0, 53, -76, -66, 125, -115, 69, -111, 80, -81, -33, -62, 84, -59, -64, -114, 113, -92, -59, 37, 106, 85, -111, -100, -19, 114, 99, 18, -9, -62, -123, -75, -22, -40, 70, -70, -46, 119, 11, -17, -71, -93, -126, -28, 116, 104, -4, -45, -58, 121, 4, 50, 76, 46, 13, -91, -76, 37, -103, 101, 57, 54, 75, 83, -124 };
for(int i=0; i<miParallelThreadCount; ++i)
{
//This snippet executes the group of compareInner methods in new threads
new Thread(() ->
{
try
{
compareInner(data, 0, data.length);
compareInner(data, 0, data.length);
compareInner(data, 0, data.length);
compareInner(data, 0, data.length);
compareInner(data, 0, data.length);
compareInner(data, 0, data.length);
compareInner(data, 0, data.length);
compareInner(data, 0, data.length);
compareInner(data, 0, data.length);
compareInner(data, 0, data.length);
compareInner(data, 0, data.length);
compareInner(data, 0, data.length);
compareInner(data, 0, data.length);
compareInner(data, 0, data.length);
compareInner(data, 0, data.length);
}
catch (Throwable lThrowable)
{
System.out.println("Something went wrong: " + lThrowable.getLocalizedMessage());
lThrowable.printStackTrace();
}
}).start();
}
System.out.println("Ran tornado");
}
private static byte[] compareInner(byte[] pTestData, int pStartIndex, int pLength)
{
//Copies the pTestData into new array as it is
byte[] lbarrData = Arrays.copyOfRange(pTestData, 0, 0 + pTestData.length);
//copies only 2ndand 3rd element from the array which is [1, 0]
byte[] lbarrVer = Arrays.copyOfRange(lbarrData, 2, 4);
//Converts the array [1, 0] into integer, which should always return 1
int liVersion = byteArrayToInt(lbarrVer);
if(liVersion != 1)
{
System.out.println("Invalid Version : " + liVersion + " data array: " + Arrays.toString(lbarrData) + " header array: " + Arrays.toString(lbarrVer));
}
return lbarrData;
}
public static final int byteArrayToInt(byte[] pSource)
{
int lValue = 0;
for (int i = 0; i < pSource.length; i++)
{
lValue += (pSource[i] & 0xff) << (8 * i);
}
return lValue;
}
}
你只需要更好地调试它。
开始运行这个单线程。然后添加一个计数器
static int x = -1; // add counter
public static final int byteArrayToInt(byte[] pSource)
{
x++ // increment counter
int lValue = 0;
for (int i = 0; i < pSource.length; i++)
{
lValue += (pSource[i] & 0xff) << (8 * i);
}
// add a print out
System.err.println("lValue: " + lValue + " counter: " + x);
return lValue;
}
一旦找到问题发生的位置(对于单线程,每次运行都应该相同),在计数器值上设置断点,例如
public static final int byteArrayToInt(byte[] pSource)
{
if (x == 5) { // replace 5
System.out.println("debug"); //add a breakpoint right here
}
int lValue = 0;
for (int i = 0; i < pSource.length; i++)
{
lValue += (pSource[i] & 0xff) << (8 * i);
}
return lValue;
}
}
这应该可以帮助您隔离单线程问题