Java 如何在循环中使用多线程
How to use multithreading in a loop in Java
这就是我想要做的。我正在 while loop
中记录来自不同传感器的数据,直到用户停止记录。我想每秒记录尽可能多的数据。传感器需要不同的时间来 return 一个值,在 200 毫秒到 3 秒之间。因此,依次调用传感器不是一种选择。
顺序调用传感器如下所示:
List<DataRow> dataRows= new ArrayList<DataRow>();
while (recording) {
DataRow dataRow = new DataRow();
dataRow.setDataA(sensorA.readData());
dataRow.setDataB(sensorB.readData());
dataRow.setDataC(sensorC.readData());
dataRows.add(dataRow);
}
根据传感器的不同,读取数据看起来(大大简化了)
public class SensorA {
public SensorAData readData(){
sensorA.startSensing();
try {
TimeUnit.MILLISECONDS.sleep(750);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return sensorA.readAndConvertByteStream();
}
}
要利用多线程,SensorA 可以在循环中实现 Callable
并接收 Future
对象吗?或者 while loop
应该放在实现接口 Runnable
的 run()
方法中吗?
基本上,即使循环已经至少进行了一次迭代,Java(或线程)是否可以写入正确的 dataRow
对象?如果没有,如何解决这个问题?
如果我正确理解您的需求,这可能是您想要的解决方案:
- 在每次迭代中,n 个传感器由 n 个并发线程读取,
- 如果所有线程都收集了传感器数据,则将新的结果行添加到列表
工作代码:
public class TestX {
private final ExecutorService pool = Executors.newFixedThreadPool(3);
private final int N = 10;
// all sensors are read sequentially and put in one row
public void testSequential() {
int total = 0;
long t = System.currentTimeMillis();
for (int i = 0; i < N; i++) {
System.out.println("starting iteration " + i);
int v1 = getSensorA(); // run in main thread
int v2 = getSensorB(); // run in main thread
int v3 = getSensorC(); // run in main thread
// collection.add( record(v1, v2, v3)
total += v1 + v2 + v3;
}
System.out.println("total = " + total + " time = " + (System.currentTimeMillis() - t) + " ms");
}
// all sensors are read concurrently and then put in one row
public void testParallel() throws ExecutionException, InterruptedException {
int total = 0;
long t = System.currentTimeMillis();
final SensorCallable s1 = new SensorCallable(1);
final SensorCallable s2 = new SensorCallable(3);
final SensorCallable s3 = new SensorCallable(3);
for (int i = 0; i < N; i++) {
System.out.println("starting iteration " + i);
Future<Integer> future1 = pool.submit(s1); // run in thread 1
Future<Integer> future2 = pool.submit(s2); // run in thread 2
Future<Integer> future3 = pool.submit(s3); // run in thread 3
int v1 = future1.get();
int v2 = future2.get();
int v3 = future3.get();
// collection.add( record(v1, v2, v3)
total += v1 + v2 + v3;
}
System.out.println("total = " + total + " time = " + (System.currentTimeMillis() - t) + " ms");
}
private class SensorCallable implements Callable<Integer> {
private final int sensorId;
private SensorCallable(int sensorId) {
this.sensorId = sensorId;
}
@Override
public Integer call() throws Exception {
switch (sensorId) {
case 1: return getSensorA();
case 2: return getSensorB();
case 3: return getSensorC();
default:
throw new IllegalArgumentException("Unknown sensor id: " + sensorId);
}
}
}
private int getSensorA() {
sleep(700);
return 1;
}
private int getSensorB() {
sleep(500);
return 2;
}
private int getSensorC() {
sleep(900);
return 2;
}
private void sleep(long ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
// ignore
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
new TestX().testSequential();
new TestX().testParallel();
}
}
并输出:
starting iteration 0
starting iteration 1
starting iteration 2
starting iteration 3
starting iteration 4
starting iteration 5
starting iteration 6
starting iteration 7
starting iteration 8
starting iteration 9
total = 50 time = 21014 ms
starting iteration 0
starting iteration 1
starting iteration 2
starting iteration 3
starting iteration 4
starting iteration 5
starting iteration 6
starting iteration 7
starting iteration 8
starting iteration 9
total = 50 time = 9009 ms
-- 编辑--
在 java 8 中你可以使用方法引用来摆脱 Callable 类 并且只写:
Future<Integer> future1 = pool.submit( this::getSensorA() );
Future<Integer> future2 = pool.submit( this::getSensorB() );
Future<Integer> future3 = pool.submit( this::getSensorC() );
这就是我想要做的。我正在 while loop
中记录来自不同传感器的数据,直到用户停止记录。我想每秒记录尽可能多的数据。传感器需要不同的时间来 return 一个值,在 200 毫秒到 3 秒之间。因此,依次调用传感器不是一种选择。
顺序调用传感器如下所示:
List<DataRow> dataRows= new ArrayList<DataRow>();
while (recording) {
DataRow dataRow = new DataRow();
dataRow.setDataA(sensorA.readData());
dataRow.setDataB(sensorB.readData());
dataRow.setDataC(sensorC.readData());
dataRows.add(dataRow);
}
根据传感器的不同,读取数据看起来(大大简化了)
public class SensorA {
public SensorAData readData(){
sensorA.startSensing();
try {
TimeUnit.MILLISECONDS.sleep(750);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return sensorA.readAndConvertByteStream();
}
}
要利用多线程,SensorA 可以在循环中实现 Callable
并接收 Future
对象吗?或者 while loop
应该放在实现接口 Runnable
的 run()
方法中吗?
基本上,即使循环已经至少进行了一次迭代,Java(或线程)是否可以写入正确的 dataRow
对象?如果没有,如何解决这个问题?
如果我正确理解您的需求,这可能是您想要的解决方案:
- 在每次迭代中,n 个传感器由 n 个并发线程读取,
- 如果所有线程都收集了传感器数据,则将新的结果行添加到列表
工作代码:
public class TestX {
private final ExecutorService pool = Executors.newFixedThreadPool(3);
private final int N = 10;
// all sensors are read sequentially and put in one row
public void testSequential() {
int total = 0;
long t = System.currentTimeMillis();
for (int i = 0; i < N; i++) {
System.out.println("starting iteration " + i);
int v1 = getSensorA(); // run in main thread
int v2 = getSensorB(); // run in main thread
int v3 = getSensorC(); // run in main thread
// collection.add( record(v1, v2, v3)
total += v1 + v2 + v3;
}
System.out.println("total = " + total + " time = " + (System.currentTimeMillis() - t) + " ms");
}
// all sensors are read concurrently and then put in one row
public void testParallel() throws ExecutionException, InterruptedException {
int total = 0;
long t = System.currentTimeMillis();
final SensorCallable s1 = new SensorCallable(1);
final SensorCallable s2 = new SensorCallable(3);
final SensorCallable s3 = new SensorCallable(3);
for (int i = 0; i < N; i++) {
System.out.println("starting iteration " + i);
Future<Integer> future1 = pool.submit(s1); // run in thread 1
Future<Integer> future2 = pool.submit(s2); // run in thread 2
Future<Integer> future3 = pool.submit(s3); // run in thread 3
int v1 = future1.get();
int v2 = future2.get();
int v3 = future3.get();
// collection.add( record(v1, v2, v3)
total += v1 + v2 + v3;
}
System.out.println("total = " + total + " time = " + (System.currentTimeMillis() - t) + " ms");
}
private class SensorCallable implements Callable<Integer> {
private final int sensorId;
private SensorCallable(int sensorId) {
this.sensorId = sensorId;
}
@Override
public Integer call() throws Exception {
switch (sensorId) {
case 1: return getSensorA();
case 2: return getSensorB();
case 3: return getSensorC();
default:
throw new IllegalArgumentException("Unknown sensor id: " + sensorId);
}
}
}
private int getSensorA() {
sleep(700);
return 1;
}
private int getSensorB() {
sleep(500);
return 2;
}
private int getSensorC() {
sleep(900);
return 2;
}
private void sleep(long ms) {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
// ignore
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
new TestX().testSequential();
new TestX().testParallel();
}
}
并输出:
starting iteration 0
starting iteration 1
starting iteration 2
starting iteration 3
starting iteration 4
starting iteration 5
starting iteration 6
starting iteration 7
starting iteration 8
starting iteration 9
total = 50 time = 21014 ms
starting iteration 0
starting iteration 1
starting iteration 2
starting iteration 3
starting iteration 4
starting iteration 5
starting iteration 6
starting iteration 7
starting iteration 8
starting iteration 9
total = 50 time = 9009 ms
-- 编辑--
在 java 8 中你可以使用方法引用来摆脱 Callable 类 并且只写:
Future<Integer> future1 = pool.submit( this::getSensorA() );
Future<Integer> future2 = pool.submit( this::getSensorB() );
Future<Integer> future3 = pool.submit( this::getSensorC() );