I am fairly new to the callable interface. I have some code which I can't get to compile at the moment and just need some help on why....
public List<String> getNonPingableRegisters (Collection<RegisterReplicationSynchTime> nonReplicatingRegisters) throws IOException {
int nThreads = 15;
final ExecutorService es = Executors.newFixedThreadPool(nThreads);
Collection<Callable<PingTask>> pingTasks = new ArrayList<Callable<PingTask>>(nonReplicatingRegisters.size());
for (RegisterReplicationSynchTime nonReplicatingRegister : nonReplicatingRegisters) {
pingTasks.add(new PingTask(nonReplicatingRegister.getRegisterName()));
}
List<Future<String>> taskResults = es.invokeAll(pingTasks);
List<String> results = new ArrayList<String>();
for (Future<String> taskResult : taskResults) {
try {
String output = taskResult.get();
if (StringUtils.isNotEmpty(output) ) {
results.add(output);
}
} catch (InterruptedException e) {
// handle accordingly
} catch (ExecutionException e) {
// handle accordingly
}
}
return results;
}
Where PingTask is ...
public class PingTask implements Callable<String> {
private String hostname = null;
public PingTask(String hostname) {
this.hostname = hostname;
}
public String call() {
Socket socket = null;
boolean reachable = false;
try {
socket = new Socket();
socket.connect(new InetSocketAddress(hostname, 139), 1000); //1 sec timeout
reachable = true;
socket.close();
} catch (IOException e) {
}
finally {
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
}
}
}
return (reachable ? "" : hostname);
}
}
The compile error is at ...
List<Future<String>> taskResults = es.invokeAll(pingTasks);
The method add(Callable) in the type Collection> is not applicable for the arguments (PingTask) StoreReplicationSynchtimeManagerImpl.java
Not sure what I need to do here to make the call to invokeAll. Would appreciate some help.
thanks
Error is not at that line.
It's at:
pingTasks.add(new PingTask(nonReplicatingRegister.getRegisterName()));
Your collection is of Callable where as your PingTask class implements Callable. Change the collection to:
Collection<Callable<String>>
Here's your mistake:
Collection<Callable<PingTask>> pingTasks = new ArrayList<Callable<PingTask>>(nonReplicatingRegisters.size());
PingTask implements Callable<String>, not Callable<PingTask>. You need to declare your list as Collection<PingTask> or Collection<Callable<String>>.
There is a type mis-match.
Collection<Callable<PingTask>> pingTasks = new ArrayList<Callable<PingTask>>
But PingTask is declared as
public class PingTask implements Callable<String>
Change collection as Collection<PingTask>
pingTasks.add(new PingTask(nonReplicatingRegister.getRegisterName()));
will cause compile time error due to Callable<String> type addition
Related
I am trying to figure out NIO in Java doing some simple client-server project.
The case is I have to concurrent clients in cached thread pool executor, who are communicating with single-threaded server using non-blocking NIO channels.
The problem is that last client cannot receive last server's sent message. It locks in infinite loop waiting for upcoming data.
ClientTask class:
public class ClientTask extends FutureTask<String> {
private Client client;
private List<String> reqList; // requests list (without last and first)
private boolean showRes; // print request results
public ClientTask(Client client, List<String> reqList, boolean showRes) {
super(() -> ClientTask.getLogWhenArrives(client, reqList, showRes));
this.client = client;
this.reqList = reqList;
this.showRes = showRes;
}
public static ClientTask create(Client c, List<String> reqList, boolean showRes) {
return new ClientTask(c, reqList, showRes);
}
private static String getLogWhenArrives(Client client, List<String> reqList, boolean showRes) {
client.connect();
String response = client.send("login " + client.getId());
if (showRes) System.out.println(response);
for (String req : reqList) {
response = client.send(req);
if (showRes) System.out.println(response);
}
String responseLog = client.send("bye and log transfer");
client.close();
return responseLog;
}
}
Client send():
public String send(String req) {
ByteBuffer reqBuffer = ByteBuffer.wrap((req + END).getBytes());
try {
channel.write(reqBuffer);
} catch (IOException e) {
e.printStackTrace();
}
return receive();
}
Client receive()
public String receive() {
StringBuilder result = new StringBuilder();
try {
inBuff.clear();
readLoop:
while (true) { // THIS LOOP WON'T END
int n = channel.read(inBuff);
if (n == -1) {
break;
}
if (n > 0) {
inBuff.flip();
CharBuffer cb = charset.decode(inBuff);
while (cb.hasRemaining()) {
char c = cb.get();
if (c == END.charAt(0)) {
break readLoop;
}
result.append(c);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
return result.toString();
}
Main:
public class Main {
public static void main(String[] args) throws Exception {
String fileName = System.getProperty("user.home") + "/PassTimeServerOptions.yaml";
Options opts = Tools.createOptionsFromYaml(fileName);
String host = opts.getHost();
int port = opts.getPort();
boolean concur = opts.isConcurMode();
boolean showRes = opts.isShowSendRes();
Map<String, List<String>> clRequests = opts.getClientsMap();
ExecutorService es = Executors.newCachedThreadPool();
List<ClientTask> ctasks = new ArrayList<>();
List<String> clogs = new ArrayList<>();
Server s = new Server(host, port);
s.startServer();
// start clients
clRequests.forEach( (id, reqList) -> {
Client c = new Client(host, port, id);
if (concur) {
ClientTask ctask = ClientTask.create(c, reqList, showRes);
ctasks.add(ctask);
es.execute(ctask);
}
});
if (concur) {
ctasks.forEach( task -> {
try {
String log = task.get();
clogs.add(log);
} catch (InterruptedException | ExecutionException exc) {
System.out.println(exc);
}
});
clogs.forEach( System.out::println);
es.shutdown();
}
s.stopServer();
System.out.println("\n=== Server log ===");
System.out.println(s.getServerLog());
}
}
Server is sending all the info and channels are open and connected.
I'm struggling with the functional style of Supplier<U>, etc and creating testable code.
So I have an InputStream that is split into chunks which are processed asynchronously, and I want to know when they are all done. To write testable code, I outsource the processing logic to its own Runnable:
public class StreamProcessor {
public CompletableFuture<Void> process(InputStream in) {
List<CompletableFuture> futures = new ArrayList<>();
while (true) {
try (SizeLimitInputStream chunkStream = new SizeLimitInputStream(in, 100)) {
byte[] data = IOUtils.toByteArray(chunkStream);
CompletableFuture<Void> f = CompletableFuture.runAsync(createTask(data));
futures.add(f);
} catch (EOFException ex) {
// end of stream reached
break;
} catch (IOException ex) {
return CompletableFuture.failedFuture(ex);
}
}
return CompletableFuture.allOf(futures.toArray(CompletableFuture<?>[]::new));
}
ChunkTask createTask(byte[] data) {
return new ChunkTask(data);
}
public class ChunkTask implements Runnable {
final byte[] data;
ChunkTask(byte[] data) {
this.data = data;
}
#Override
public void run() {
try {
// do something
} catch (Exception ex) {
// checked exceptions must be wrapped
throw new RuntimeException(ex);
}
}
}
}
This works well, but poses two problems:
The processing code cannot return anything; it's a Runnable after all.
Any checked exceptions caught inside ChunkTask.run() must be wrapped into a RuntimeException. Unwrapping the failed combined CompletableFuture returns the RuntimeException which needs to be unwrapped again to reach the original cause - in contrast to the IOException.
So I'm looking for a way to do this with CompletableFuture.supplyAsync(), but I can't figure out how to do this without lambdas (bad to test) or to return a CompletableFuture.failedFuture() from the processing logic.
I can think of two approaches:
1. With supplyAsync:
When using CompletableFuture.supplyAsync, you need a supplier instead of a runnable:
public static class ChunkTask implements Supplier<Object> {
final byte[] data;
ChunkTask(byte[] data) {
this.data = data;
}
#Override
public Object get() {
Object result = ...;
// Do something or throw an exception
return result;
}
}
and then:
CompletableFuture
.supplyAsync( new ChunkTask( data ) )
.whenComplete( (result, throwable) -> ... );
If an exception happens in Supplier.get(), it will b e propagated and you can see it in CompletableFuture.whenComplete, CompletableFuture.handle or CompletableFuture.exceptionally.
2. Passing a CompletableFuture to the thread
You can pass a CompletableFuture to ChunkTask:
public class ChunkTask implements Runnable {
final byte[] data;
private final CompletableFuture<Object> future;
ChunkTask(byte[] data, CompletableFuture<Object> future) {
this.data = data;
this.future = future;
}
#Override
public void run() {
try {
Object result = null;
// do something
future.complete( result );
} catch (Throwable ex) {
future.completeExceptionally( ex );
}
}
}
Then the logic becomes:
while (true) {
CompletableFuture<Object> f = new CompletableFuture<>();
try (SizeLimitInputStream chunkStream = new SizeLimitInputStream(in, 100)) {
byte[] data = IOUtils.toByteArray(chunkStream);
startThread(new ChunkTask(data, f));
futures.add(f);
} catch (EOFException ex) {
// end of stream reached
break;
} catch (IOException ex) {
f.completeExceptionally( ex );
return f;
}
}
Probably, Number 2 is the one that gives you more flexibility on how to manage the exception.
public class SOQuestion {
private class TaskResult1 {//some pojo
}
private class TaskResult2{// some other pojo
}
private class Task1 implements Callable<TaskResult1> {
public TaskResult1 call() throws InterruptedException {
// do something...
return new TaskResult1();
}
}
private class Task2 implements Callable<TaskResult2> {
public TaskResult2 call() throws InterruptedException {
// do something else...
return new TaskResult2();
}
}
private void cancelFuturesTask1(List<Future<TaskResult1>> futureList ){
for(Future<TaskResult1> future: futureList){
if(future.isDone())
{
continue;
} else
{
System.out.println("cancelling futures.....Task1.");
future.cancel(true);
}
}
}
private void cancelFuturesTask2(List<Future<TaskResult2>> futureList ){
for(Future<TaskResult2> future: futureList){
if(future.isDone())
{
continue;
} else
{
System.out.println("cancelling futures.....Task2.");
future.cancel(true);
}
}
}
void runTasks() {
ExecutorService executor = Executors.newFixedThreadPool(4);
CompletionService<TaskResult1> completionService1 = new ExecutorCompletionService<TaskResult1>(executor);
List<Future<TaskResult1>> futuresList1 = new ArrayList<Future<TaskResult1>>();
for (int i =0 ;i<10; i++) {
futuresList1.add(completionService1.submit(new Task1()));
}
for (int i = 0; i< 10; i++) {
try {
Future<TaskResult1> f = completionService1.take();
System.out.print(f.get());
System.out.println("....Completed..first one.. cancelling all others.");
cancelFuturesTask1(futuresList1);
} catch (InterruptedException e) {
System.out.println("Caught interrruption....");
break;
} catch (CancellationException e) {
System.out.println("Cancellation execution....");
break;
} catch (ExecutionException e) {
System.out.println("Execution exception....");
break;
}
}
CompletionService<TaskResult2> completionService2 = new ExecutorCompletionService<TaskResult2>(executor);
List<Future<TaskResult2>> futuresList2 = new ArrayList<Future<TaskResult2>>();
try{
for (int i =0 ;i<10; i++) {
futuresList2.add(completionService2.submit(new Task2()));
}
for (int i = 0; i< 10; i++) {
try {
Future<TaskResult2> f = completionService2.take();
System.out.print(f.get());
System.out.println("....Completed..first one.. cancelling all others.");
cancelFuturesTask2(futuresList2);
} catch (InterruptedException e) {
System.out.println("Caught interrruption....");
break;
} catch (CancellationException e) {
System.out.println("Cancellation execution....");
break;
} catch (ExecutionException e) {
System.out.println("Execution exception....");
break;
}
}
}catch(Exception e){
}
executor.shutdown();
}
}
As seen in the example, there is some repetition. I want to use Generics and wild card to generalize objects and re-use some methods.
My specific ask would be "cancelFuturesTask1" and "cancelFuturesTask2". Both methods do the same thing. How can I generalize them?
I read this: https://docs.oracle.com/javase/tutorial/java/generics/subtyping.html
I created a base class "TaskResult" extended "TaskResult1" and "TaskResult2"
private class TaskResult1 extends TaskResult
private class TaskResult2 extends TaskResult
and then use
List<Futures<? extends TaskResult>>
It gives me complication error and I am having some confusion in extending the concept to List<Futures<?>> in this case.
Any pointers or explanation on how to do that will help here.
Thanks in advance, let me know if you need some clarification.
This compiles fine for me, let me know if you get errors on it also.
public class FutureTest
{
public void cancelAll( Future<?> ... futures ) {
for( Future<?> f : futures ) {
if( !f.isDone() ) {
Logger.getLogger(FutureTest.class.getName()).log(
Level.INFO, "Canceling {0}", f);
f.cancel(true);
}
}
}
public <T extends Task1 & Task2> void cancelAll( List<Future<T>> futures ) {
cancelAll( futures.toArray( new Future[futures.size()]) );
}
}
interface Task1 {}
interface Task2 {}
For a more specific type, see my second method. You can do it with a Generic Method and Bounded Type Parameter, but only if all but one type are interfaces. Java doesn't support multiple inheritance, so you can't write one method that takes multiple (not covariant) class types. That's why I think unbounded (wildcard, "<?>") methods like the first example are better here.
https://docs.oracle.com/javase/tutorial/java/generics/boundedTypeParams.html
I have a problem with my code. Code is about to find gateways/subnets and if program finds one it returns it to a class that called "call()" method. That part works fine but problem is that I want to pass ID of gateway(you know if gateway was 192.168.1.1 , it will also pass number 1 to class that fills vector of founded gateways). Problem is that for some reason vector that holds IDs of gateways is empty. Can you give me a clue how to fix problem ? Best regards.
Here is code that I used in my project:
int GateWayKey = 1;
int GateWayKeyStop=254;
String ip="";
StoredGW FoundedGW = new StoredGW();
int SubNetKey = 2;
int SubNetKeyStop = 254;
Vector <Integer> AllGateWays= new Vector <Integer>();
Vector <Future<String>> AllSQLs = new Vector <Future<String>>();
final int NUM_THREADS = Runtime.getRuntime().availableProcessors();
ExecutorService exec = Executors.newFixedThreadPool(NUM_THREADS);
public void run() {
for (;GateWayKey<=GateWayKeyStop;GateWayKey++){
ip="192.168."+GateWayKey+".1";
AllSQLs.add(exec.submit((new PingTask(ip,GateWayKey))));
}
AllGateWays = FoundedGW.GiveMeGWs();
for (int j : AllGateWays){
for (;SubNetKey<=SubNetKeyStop;SubNetKey++){
ip="192.168."+j+"."+SubNetKey;
AllSQLs.add (exec.submit(new PingTask(ip,null))));
}
exec.shutdown();
}
Here is class that preform pinging and storing ID of gateway:
public class PingTask implements Callable <String> {
String ips;
int GateWay;
public PingTask (){
}
public PingTask (String ip, int GateWayKey){
ips=ip;
GateWay=GateWayKey;
}
public String call(){
InetAddress address;
try {
address = InetAddress.getByName(ips);
try {
if (address.isReachable(5000)) {
StoredGW GWs = new StoredGW();
GWs.addNewGW(GateWay);
} else {
return null;
}
} catch (IOException e) {
return null;
}
} catch (UnknownHostException e) {
return null;
}
}
}
and here is class where I store GateWays
public class StoredGW {
Vector <Integer> AllFoundedGWs= new Vector<Integer>();
public void addNewGW(int i){
AllFoundedGWs.add(i);
}
public Vector<Integer> GiveMeGWs(){
return AllFoundedGWs;
}
}
The problem is here:
StoredGW GWs = new StoredGW();
GWs.addNewGW(GateWay);
You make a new StoreGW (as local variable) and then you throw it away. Instead use, FoundedGW. You have to make sure it is visible to your task, you might have to pass it as a constructor argument so that it can be used within your task.
Try this:
public class PingTask implements Callable <String> {
String ips;
int GateWay;
StoredGW store;
public PingTask (){
}
public PingTask (String ip, int GateWayKey, StoredGW store){
ips=ip;
GateWay=GateWayKey;
this.store = store;
}
public String call(){
InetAddress address;
try {
address = InetAddress.getByName(ips);
try {
if (address.isReachable(5000)) {
store.addNewGW(GateWay);
} else {
return null;
}
} catch (IOException e) {
return null;
}
} catch (UnknownHostException e) {
return null;
}
}
}
Then you can call it this way:
AllSQLs.add(exec.submit((new PingTask(ip,GateWayKey, FoundedGW))));
As an unrelated side note, you need to take a look at the standard for Java naming conventions, it'll make your code easier for others to understand.
I have a program that performs lots of calculations and reports them to a file frequently. I know that frequent write operations can slow a program down a lot, so to avoid it I'd like to have a second thread dedicated to the writing operations.
Right now I'm doing it with this class I wrote (the impatient can skip to the end of the question):
public class ParallelWriter implements Runnable {
private File file;
private BlockingQueue<Item> q;
private int indentation;
public ParallelWriter( File f ){
file = f;
q = new LinkedBlockingQueue<Item>();
indentation = 0;
}
public ParallelWriter append( CharSequence str ){
try {
CharSeqItem item = new CharSeqItem();
item.content = str;
item.type = ItemType.CHARSEQ;
q.put(item);
return this;
} catch (InterruptedException ex) {
throw new RuntimeException( ex );
}
}
public ParallelWriter newLine(){
try {
Item item = new Item();
item.type = ItemType.NEWLINE;
q.put(item);
return this;
} catch (InterruptedException ex) {
throw new RuntimeException( ex );
}
}
public void setIndent(int indentation) {
try{
IndentCommand item = new IndentCommand();
item.type = ItemType.INDENT;
item.indent = indentation;
q.put(item);
} catch (InterruptedException ex) {
throw new RuntimeException( ex );
}
}
public void end(){
try {
Item item = new Item();
item.type = ItemType.POISON;
q.put(item);
} catch (InterruptedException ex) {
throw new RuntimeException( ex );
}
}
public void run() {
BufferedWriter out = null;
Item item = null;
try{
out = new BufferedWriter( new FileWriter( file ) );
while( (item = q.take()).type != ItemType.POISON ){
switch( item.type ){
case NEWLINE:
out.newLine();
for( int i = 0; i < indentation; i++ )
out.append(" ");
break;
case INDENT:
indentation = ((IndentCommand)item).indent;
break;
case CHARSEQ:
out.append( ((CharSeqItem)item).content );
}
}
} catch (InterruptedException ex){
throw new RuntimeException( ex );
} catch (IOException ex) {
throw new RuntimeException( ex );
} finally {
if( out != null ) try {
out.close();
} catch (IOException ex) {
throw new RuntimeException( ex );
}
}
}
private enum ItemType {
CHARSEQ, NEWLINE, INDENT, POISON;
}
private static class Item {
ItemType type;
}
private static class CharSeqItem extends Item {
CharSequence content;
}
private static class IndentCommand extends Item {
int indent;
}
}
And then I use it by doing:
ParallelWriter w = new ParallelWriter( myFile );
new Thread(w).start();
/// Lots of
w.append(" things ").newLine();
w.setIndent(2);
w.newLine().append(" more things ");
/// and finally
w.end();
While this works perfectly well, I'm wondering:
Is there a better way to accomplish this?
Your basic approach looks fine. I would structure the code as follows:
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
public interface FileWriter {
FileWriter append(CharSequence seq);
FileWriter indent(int indent);
void close();
}
class AsyncFileWriter implements FileWriter, Runnable {
private final File file;
private final Writer out;
private final BlockingQueue<Item> queue = new LinkedBlockingQueue<Item>();
private volatile boolean started = false;
private volatile boolean stopped = false;
public AsyncFileWriter(File file) throws IOException {
this.file = file;
this.out = new BufferedWriter(new java.io.FileWriter(file));
}
public FileWriter append(CharSequence seq) {
if (!started) {
throw new IllegalStateException("open() call expected before append()");
}
try {
queue.put(new CharSeqItem(seq));
} catch (InterruptedException ignored) {
}
return this;
}
public FileWriter indent(int indent) {
if (!started) {
throw new IllegalStateException("open() call expected before append()");
}
try {
queue.put(new IndentItem(indent));
} catch (InterruptedException ignored) {
}
return this;
}
public void open() {
this.started = true;
new Thread(this).start();
}
public void run() {
while (!stopped) {
try {
Item item = queue.poll(100, TimeUnit.MICROSECONDS);
if (item != null) {
try {
item.write(out);
} catch (IOException logme) {
}
}
} catch (InterruptedException e) {
}
}
try {
out.close();
} catch (IOException ignore) {
}
}
public void close() {
this.stopped = true;
}
private static interface Item {
void write(Writer out) throws IOException;
}
private static class CharSeqItem implements Item {
private final CharSequence sequence;
public CharSeqItem(CharSequence sequence) {
this.sequence = sequence;
}
public void write(Writer out) throws IOException {
out.append(sequence);
}
}
private static class IndentItem implements Item {
private final int indent;
public IndentItem(int indent) {
this.indent = indent;
}
public void write(Writer out) throws IOException {
for (int i = 0; i < indent; i++) {
out.append(" ");
}
}
}
}
If you do not want to write in a separate thread (maybe in a test?), you can have an implementation of FileWriter which calls append on the Writer in the caller thread.
One good way to exchange data with a single consumer thread is to use an Exchanger.
You could use a StringBuilder or ByteBuffer as the buffer to exchange with the background thread. The latency incurred can be around 1 micro-second, doesn't involve creating any objects and which is lower using a BlockingQueue.
From the example which I think is worth repeating here.
class FillAndEmpty {
Exchanger<DataBuffer> exchanger = new Exchanger<DataBuffer>();
DataBuffer initialEmptyBuffer = ... a made-up type
DataBuffer initialFullBuffer = ...
class FillingLoop implements Runnable {
public void run() {
DataBuffer currentBuffer = initialEmptyBuffer;
try {
while (currentBuffer != null) {
addToBuffer(currentBuffer);
if (currentBuffer.isFull())
currentBuffer = exchanger.exchange(currentBuffer);
}
} catch (InterruptedException ex) { ... handle ... }
}
}
class EmptyingLoop implements Runnable {
public void run() {
DataBuffer currentBuffer = initialFullBuffer;
try {
while (currentBuffer != null) {
takeFromBuffer(currentBuffer);
if (currentBuffer.isEmpty())
currentBuffer = exchanger.exchange(currentBuffer);
}
} catch (InterruptedException ex) { ... handle ...}
}
}
void start() {
new Thread(new FillingLoop()).start();
new Thread(new EmptyingLoop()).start();
}
}
Using a LinkedBlockingQueue is a pretty good idea. Not sure I like some of the style of the code... but the principle seems sound.
I would maybe add a capacity to the LinkedBlockingQueue equal to a certain % of your total memory.. say 10,000 items.. this way if your writing is going too slow, your worker threads won't keep adding more work until the heap is blown.
I know that frequent write operations
can slow a program down a lot
Probably not as much as you think, provided you use buffering.