我有同样的问题。我通过启动两个线程解决了这个问题:一个写一个等待特定的时间。根据完成的第一个,写入是成功还是超时。这是我使用的不同类:
ByteWriter:通用字节写入的接口(我希望能够从 JSSC 切换到任何其他框架
package net.femtoparsec.jssc;
import java.io.IOException;
public interface ByteWriter {
void write(byte[] bytes) throws IOException;
void write(byte oneByte) throws IOException;
void write(byte[] bytes, long timeout) throws IOException, InterruptedException;
void write(byte oneByte, long timeout) throws IOException, InterruptedException;
void cancelWrite() throws IOException;
}
JsscByteWriter : Jssc 的 ByteWriter 实现
package net.femtoparsec.jssc;
import jssc.SerialPort;
import jssc.SerialPortException;
import java.io.IOException;
public class JsscByteWriter implements ByteWriter {
private final SerialPort serialPort;
public JsscByteWriter(SerialPort serialPort) {
this.serialPort = serialPort;
}
@Override
public void cancelWrite() throws IOException {
try {
serialPort.purgePort(SerialPort.PURGE_TXABORT);
serialPort.purgePort(SerialPort.PURGE_TXCLEAR);
} catch (SerialPortException e) {
throw new IOException(e);
}
}
@Override
public void write(byte[] bytes) throws IOException {
try {
serialPort.writeBytes(bytes);
} catch (SerialPortException e) {
throw new IOException(e);
}
}
@Override
public void write(byte oneByte) throws IOException {
try {
serialPort.writeByte(oneByte);
} catch (SerialPortException e) {
throw new IOException(e);
}
}
@Override
public void write(byte[] bytes, long timeout) throws IOException, InterruptedException {
if (timeout <= 0) {
this.write(bytes);
}
else {
new TimedOutByteWriting(this, bytes, timeout).write();
}
}
@Override
public void write(byte oneByte, long timeout) throws IOException, InterruptedException {
if (timeout <= 0) {
this.write(oneByte);
}
else {
new TimedOutByteWriting(this, oneByte, timeout).write();
}
}
}
TimedOutByteWriting :执行写入超时的类。
package net.femtoparsec.jssc;
import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.*;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
class TimedOutByteWriting {
private final ByteWriter byteWriter;
private final boolean onlyOneByte;
private final byte oneByte;
private final byte[] bytes;
private final long timeout;
private static final ExecutorService EXECUTOR_SERVICE = Executors.newCachedThreadPool(r -> {
Thread t = new Thread(r, "TimedOutByteWriting Thread");
t.setDaemon(true);
return t;
});
TimedOutByteWriting(ByteWriter byteWriter, byte oneByte, long timeout) {
if (timeout <= 0) {
throw new IllegalArgumentException("Invalid time out value : "+timeout+". Must be greater than 0");
}
this.byteWriter = Objects.requireNonNull(byteWriter, "byteWriter");
this.bytes = null;
this.oneByte = oneByte;
this.timeout = timeout;
this.onlyOneByte = true;
}
TimedOutByteWriting(ByteWriter byteWriter, byte[] bytes, long timeout) {
if (timeout <= 0) {
throw new IllegalArgumentException("Invalid time out value : "+timeout+". Must be greater than 0");
}
this.byteWriter = Objects.requireNonNull(byteWriter, "byteWriter");
this.bytes = Objects.requireNonNull(bytes, "bytes");
this.timeout = timeout;
this.oneByte = 0;
this.onlyOneByte = false;
}
void write() throws IOException, InterruptedException {
final Lock lock = new ReentrantLock();
final Condition condition = lock.newCondition();
final Result result = new Result();
final Future<?> writeThread = EXECUTOR_SERVICE.submit(new WriteRunnable(result, lock, condition));
final Future<?> timeoutThread = EXECUTOR_SERVICE.submit(new TimeoutRunnable(result, lock, condition));
lock.lock();
try {
if (!result.timedout && !result.writeDone) {
try {
condition.await();
} catch (InterruptedException e) {
writeThread.cancel(true);
timeoutThread.cancel(true);
throw e;
}
}
if (!result.writeDone) {
byteWriter.cancelWrite();
}
else {
timeoutThread.cancel(true);
}
}
finally {
lock.unlock();
}
result.handleResult();
}
private abstract class TimedOutByteWritingRunnable implements Runnable {
protected final Result result;
final Lock lock;
final Condition condition;
TimedOutByteWritingRunnable(Result result, Lock lock, Condition condition) {
this.result = result;
this.lock = lock;
this.condition = condition;
}
}
private class WriteRunnable extends TimedOutByteWritingRunnable {
private WriteRunnable(Result result, Lock lock, Condition condition) {
super(result, lock, condition);
}
@Override
public void run() {
IOException exception;
try {
if (onlyOneByte) {
byteWriter.write(oneByte);
} else {
byteWriter.write(bytes);
}
exception = null;
} catch (IOException e) {
exception = e;
}
lock.lock();
try {
result.writeException = exception;
result.writeDone = exception == null;
condition.signalAll();
} finally {
lock.unlock();
}
}
}
private class TimeoutRunnable extends TimedOutByteWritingRunnable {
private TimeoutRunnable(Result result, Lock lock, Condition condition) {
super(result, lock, condition);
}
@Override
public void run() {
boolean interrupted;
try {
TimeUnit.MILLISECONDS.sleep(timeout);
interrupted = false;
} catch (InterruptedException e) {
interrupted = true;
}
lock.lock();
try {
result.timedout = !interrupted;
condition.signalAll();
} finally {
lock.unlock();
}
}
}
private static class Result {
IOException writeException;
boolean writeDone = false;
boolean timedout = false;
void handleResult() throws IOException {
if (writeDone) {
return;
}
if (timedout) {
throw new TimeoutException("Write timed out");
}
else if (writeException != null) {
throw writeException;
}
}
}
}
和 TimeOutException
package net.femtoparsec.jssc;
import java.io.IOException;
public class TimeoutException extends IOException {
public TimeoutException(String message) {
super(message);
}
}
然后,只需创建一个 JsscByteWriter 并使用带有 timeout 参数的方法来写入超时。