Why use poll() instead of take() in zookeeper WorkerSender - java

I have been reading zookeeper source code and found that when fetching ToSend message from the queue in FastLeaderElection.WorkerSender, they use poll() instead of take(). Why?
Is poll() better?
Searching the git history, I've found that it started using take(), so there must have been a reason for changing to poll().
public void run() {
while (!stop) {
try {
ToSend m = sendqueue.poll(3000, TimeUnit.MILLISECONDS);
if (m == null) {
continue;
}
process(m);
} catch (InterruptedException e) {
break;
}
}
LOG.info("WorkerSender is down");
}

TL;DR: To check the stop flag.
Change made for ZOOKEEPER-498: Diff of FastLeaderElection.java
Old code:
class WorkerReceiver implements Runnable {
QuorumCnxManager manager;
WorkerReceiver(QuorumCnxManager manager) {
this.manager = manager;
}
public void run() {
Message response;
while (true) {
// Sleeps on receive
try{
response = manager.recvQueue.take();
// Receive new message
LOG.debug("Receive new message.");
New code:
class WorkerReceiver implements Runnable {
volatile boolean stop;
QuorumCnxManager manager;
WorkerReceiver(QuorumCnxManager manager) {
this.stop = false;
this.manager = manager;
}
public void run() {
Message response;
while (!stop) {
// Sleeps on receive
try{
response = manager.recvQueue.poll(3000, TimeUnit.MILLISECONDS);
if(response == null) continue;
// Receive new message
LOG.debug("Receive new message.");
they use poll() instead of take(). Why ?
So they can check the new stop flag every 3 seconds.

Related

Sending requests with buffer when service down

I have feign service:
#FeignClient(url = "email-service")
public interface EmailFeign {
#RequestMapping(method = POST, path = "/")
void postEmail(#RequestBody Email email);
#RequestMapping(method = PUT, path = "/")
void putEmail(#RequestBody Email email);
}
Requirements:
No need to wait for the method execute (async).
When email-service is down it is required to save all mails and send them after enabling email-service.
Email-service is considered down after the first unsuccessful
attempt to send mail.
If email-service is down is required to check email-service each
DELAY seconds.
It is allowed to send messages in one thread but it is preferable to
send messages in several threads.
I resolved it with BlockingDeque and DemonThread:
public void run() {
while (true) {
try {
if (queue.isEmpty()) {
synchronized(this) {
wait();
}
}
Runnable poll = queue.poll();
if (!tryRun(poll)) {
queue.addFirst(poll);
//I use notify when queue is not empty so I can't use wait() in this case
Thread.sleep(delay);
}
} catch (Exception e) {}
}
}
I want to find smarter solution. Perhaps with one of the ServiceExecutor implementations.
Thanks.
Edit:
One more solution
public class PausableThreadPoolExecutor extends ThreadPoolExecutor {
private final long delay;
private volatile boolean isPaused = false;
private ReentrantLock pauseLock = new ReentrantLock();
private Condition unpaused = pauseLock.newCondition();
public PausableThreadPoolExecutor(long delay, int threadCount) {
super(1, threadCount, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>());
this.delay = delay;
}
#Override
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
pauseLock.lock();
pauseLock.unlock();
}
#Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
//If exception has occurred
if (t != null) {
isPaused = true;
pauseLock.lock();
// Double Checked Locking
if (isPaused) {
try {
unpaused.await(delay, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
log.error("Pause error", e);
} finally {
isPaused = false;
pauseLock.unlock();
}
}
execute(r);
}
}
}

Java BlockingQueue Messages Lagging issue between threads

I have implemented a two player game with thread pool of sockets. each player connects to their own thread. I added a message Queue system according to this article.
Problem is the messages are lagging. the first respond from the first player is added to messageQueue as expected. But second player doesn't received it by calling poll() it only receives null yet.
And then the second player responds the second player receives the first players message. My intention is to send the message to second player before his/her response.
I must be doing some mistake or I have neglected some important concept.
Can you please help me find it?
My Code goes like this, there are two Classes related to this, GameRunnable.java and Game.java. I have omitted some code to simplify this mess.
In GameRunnable class ;
public static final Map<GamerRunnable, BlockingQueue<String>> messageQueues = new ConcurrentHashMap<>();
public static final Map<String, GamerRunnable> gameQueue = new ConcurrentHashMap<>();
private Game game;
public void run() {
System.out.println
(this.setGameInstance(clientSocket, readerIn, output) ? "OK": "FAILED");
messageQueues.put(this, new ArrayBlockingQueue<String>(100));
// If player 1
this.game.initGame(this);
// If Player 2
this.game.initGame(this);
}
public static GamerRunnable getGameThreadByName(String name) {
return gameQueue.get(name);
}
public String getName() {
return this.name;
}
in Game.java
public Game(Socket clientSocket, BufferedReader readIn, OutputStream output) {
this.sockGamer = clientSocket;
try {
this.out = output;
this.inGamer = readIn;
} catch(Exception e) {
e.printStackTrace();
}
public void sendToGamer(String msg) {
try {
this.out.write((msg+"\n").getBytes());
this.out.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void initGame(GamerRunnable game) {
try {
boolean messageLoop = true;
String line1 = null;
String line2 = null;
while (messageLoop) {
line1 = inGamer.readLine();
if (line1 != null) {
System.out.println("Gamer says: "+line1);
GamerRunnable gamer2 = null;
if (game.getName().equals("red")) {
gamer2 = GamerRunnable.getGameThreadByName("black");
}
else if (game.getName().equals("black")) {
gamer2 = GamerRunnable.getGameThreadByName("red");
}
if (gamer2 != null) {
System.out.println("Adding to Queue");
GamerRunnable.messageQueues.get(gamer2).offer(line1);
}
}
line2 = GamerRunnable.messageQueues.get(game).poll();
if (line2 != null) {
//receiving from Queue
System.out.println(line2);
game.getGameInstance().sendToGamer(line2);
}
}
Due to network latency you may need a short delay to wait for the first message to arrive on the queue. Try poll(time, unit) instead. This will wait for the specified time for a message to appear on the queue. If nothing is there it will return a null like poll() is now. A user will probably not notice a 500ms to 1s delay if no message is available.

Why the roster isn't added on both the sides?

user-a sends a subscription request to user-b. Subscription mode has been set to accept_all. Also, packet listener has been registered for both the users.
When user-a sends a request to user-b this method is called :
private void searchUser(java.awt.event.ActionEvent evt) {
try {
String userToSearch = jTextField1.getText();
if(!xmppParamInit) {
initUXmppP();
xmppParamInit = true;
}
Presence subscribe = new Presence(Presence.Type.subscribe);
userToSearch += "#localhost";
subscribe.setTo(userToSearch);
ofConnection.sendPacket(subscribe); // Send the 'subscribe' packet
}catch(Exception exc) {
exc.printStackTrace();
}
}
Prior to this method, following are called :
private void startPLThread() { // start packet-listener-thread
Runnable r = new Runnable() {
#Override
public void run() {
startPL();
}
};
new Thread(r,"packet listener thread").start();
}
private void startPL() {
PacketListener pListener = new PacketListener() {
#Override
public void processPacket(Packet packet) {System.out.println("Inside process packet");
if(packet instanceof Presence) {
Presence presence = (Presence) packet;
Presence subscription = new Presence(Presence.Type.subscribe);
subscription.setTo(presence.getFrom());
System.out.println("presence.getFrom : " + presence.getFrom());
ofConnection.sendPacket(subscription);
}
}
};
PacketFilter pFilter = new PacketFilter() {
#Override
public boolean accept(Packet packet) {
return true;
}
};
ofConnection.addPacketListener(pListener, pFilter);
}
The problem is user-a can see user-b in his roster but user-b cannot see user-a in its roster. I do not understand the reason for this. What could be the problem ?
Subscription mode has been set to accept_all in this method that is called from within search user :
private void initUXmppP() { // Initialize user-xmpp-parameters
Roster roster = ofConnection.getRoster();
roster.setSubscriptionMode(Roster.SubscriptionMode.accept_all);
}
It is a GUI application and I tried keeping both the users online

How can I make the thread sleep for a while and then process all the messages?

I'm writing an Android app that uses two threads. One is UI thread and the other handles server communication. Is it possible for the other thread to wait for a specified amount of time and then process all the messages that have arrived and then wait again?
I need this so that I can collect different data and send it to server in one session.
I've build my thread with HandlerThread but now I'm stuck. Can anyone point me to the right direction?
This is the code I'm using inside the second thread:
public synchronized void waitUntilReady() {
serverHandler = new Handler(getLooper()){
public void handleMessage(Message msg) { // msg queue
switch(msg.what) {
case TEST_MESSAGE:
testMessage(msg);
break;
case UI_MESSAGE:
break;
case SERVER_MESSAGE:
break;
default:
System.out.println(msg.obj != null ? msg.obj.getClass().getName() : "is null");
break;
}
}
};
}
EDIT:
I resolved my issue by going with Thread instead of HandlerThread and using queue.
I'm new to programming so I apologize for any horrenous errors but here's the code I ended up using.
public class ServiceThread extends Thread {
// TODO maybe set the thread priority to background?
static ServiceThread sThread = new ServiceThread(); // service thread instance
private volatile Handler mainHandler;
//
public Thread mainThread;
private boolean OK = true;
public Queue<MessageService> msgQueue;
private ThreadPoolExecutor exec;
private ServiceThread() { }
#Override
public void run() {
synchronized (this){
msgQueue = new ConcurrentLinkedQueue<MessageService>();
notifyAll();
}
mainHandler = new Handler(Looper.getMainLooper());
ThreadPoolExecutor exPool = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);
exec = exPool;
// MAIN LOOP
try {
while(OK) {
getMessagesFromQueue();
Thread.sleep(3000);
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//end of loop
}
public void ProcessMessage(MessageService message) {
System.err.println("ProcessMessage with command: " + message.command);
}
/** Called from the Main thread. Waits until msgQueue is instantiated and then passes the reference
* #return Message Queue
*/
public Queue<MessageService> sendQueue() {
synchronized (this){
while(msgQueue == null) {
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block -- move the try block!
e.printStackTrace();
}
}
}
return msgQueue;
}
public void setOkFalse () {
if (OK == true)
OK = false;
}
// Message handling methods
/** Priority message from UI thread, processed in another thread ASAP.
* Should be used on commands like getBigPicture or getPics when cached pics are running out
* or upload picture etc.
* #param message - Message should always be MessageService class
* TODO check that it really is.
*/
public void prioTask (MessageService message) {
final MessageService taskMsg = message;
Runnable task = new Runnable() {
#Override
public void run(){
ProcessMessage(taskMsg);
}
};
exec.execute(task);
}
/**
* Gets messages from queue, puts them in the list, saves the number of messages retrieved
* and sends them to MessageService.handler(int commands, list messageList)
* (method parameters may change and probably will =) )
*/
public void getMessagesFromQueue() {
int commands = 0;
ArrayList <MessageService> msgList = new ArrayList <MessageService>();
while(!msgQueue.isEmpty()) {
if(msgQueue.peek() instanceof MessageService) {
//put into list?
msgList.add(msgQueue.remove());
commands++;
} else {
//Wrong type of message
msgQueue.remove();
System.err.println("getMessagesFromQueue: Message not" +
" instanceof MessageService, this shouldn't happen!");
}
}
if (commands > 0) {
HTTPConnection conn;
try {
conn = new HTTPConnection();
MessageService.handleSend(commands, msgList, conn);
conn.disconnect();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
P.S. This is also my first post here. Should I mark it solved or something? How?

Single Producer Single Consumer now I Need Multiple Consumers

I have a Situation where I wrote a simple Producer Consumer model for reading in chunks of data from Bluetooth then every 10k bytes I write that to file. I used a standard P-C Model using a Vector as my message holder. So how do I change this so that multiple Thread consumers can read the same messages, I think the term would be Multicaster? I am actually using this on an Android phone so JMS is probably not an option.
static final int MAXQUEUE = 50000;
private Vector<byte[]> messages = new Vector<byte[]>();
/**
* Put the message in the queue for the Consumer Thread
*/
private synchronized void putMessage(byte[] send) throws InterruptedException {
while ( messages.size() == MAXQUEUE )
wait();
messages.addElement( send );
notify();
}
/**
* This method is called by the consumer to see if any messages in the queue
*/
public synchronized byte[] getMessage()throws InterruptedException {
notify();
while ( messages.size() == 0 && !Thread.interrupted()) {
wait(1);
}
byte[] message = messages.firstElement();
messages.removeElement( message );
return message;
}
I am referencing code from an Oreilly book Message Parser section
Pub-sub mechanism is definitely the way to achieve what you want. I am not sure why developing for Android will restrict you from using JMS, which is as simple a spec as it gets. Check out
this thread on SO.
You should definitely use a queue instead of the Vector!
Give every thread its own queue and, when a new message is received, add() the new message to every thread's queue. For flexibility, a listener pattern may be useful, too.
Edit:
Ok, I feel I should add an example, too:
(Classical observer pattern)
This is the interface, all consumers must implement:
public interface MessageListener {
public void newMessage( byte[] message );
}
A producer might look like this:
public class Producer {
Collection<MessageListener> listeners = new ArrayList<MessageListener>();
// Allow interested parties to register for new messages
public void addListener( MessageListener listener ) {
this.listeners.add( listener );
}
public void removeListener( Object listener ) {
this.listeners.remove( listener );
}
protected void produceMessages() {
byte[] msg = new byte[10];
// Create message and put into msg
// Tell all registered listeners about the new message:
for ( MessageListener l : this.listeners ) {
l.newMessage( msg );
}
}
}
And a consumer class could be (using a blocking queue which does all that wait()ing and notify()ing for us):
public class Consumer implements MessageListener {
BlockingQueue< byte[] > queue = new LinkedBlockingQueue< byte[] >();
// This implements the MessageListener interface:
#Override
public void newMessage( byte[] message ) {
try {
queue.put( message );
} catch (InterruptedException e) {
// won't happen.
}
}
// Execute in another thread:
protected void handleMessages() throws InterruptedException {
while ( true ) {
byte[] newMessage = queue.take();
// handle the new message.
}
}
}
This is what I came up with as an example when digging through some code and modifiying some existing examples.
package test.messaging;
import java.util.ArrayList;
import java.util.concurrent.LinkedBlockingQueue;
public class TestProducerConsumers {
static Broker broker;
public TestProducerConsumers(int maxSize) {
broker = new Broker(maxSize);
Producer p = new Producer();
Consumer c1 = new Consumer("One");
broker.consumers.add(c1);
c1.start();
Consumer c2 = new Consumer("Two");
broker.consumers.add(c2);
c2.start();
p.start();
}
// Test Producer, use your own message producer on a thread to call up
// broker.insert() possibly passing it the message instead.
class Producer extends Thread {
#Override
public void run() {
while (true) {
try {
broker.insert();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Consumer extends Thread {
String myName;
LinkedBlockingQueue<String> queue;
Consumer(String m) {
this.myName = m;
queue = new LinkedBlockingQueue<String>();
}
#Override
public void run() {
while(!Thread.interrupted()) {
try {
while (queue.size() == 0 && !Thread.interrupted()) {
;
}
while (queue.peek() == null && !Thread.interrupted()) {
;
}
System.out.println("" + myName + " Consumer: " + queue.poll());
} catch (Exception e) { }
}
}
}
class Broker {
public ArrayList<Consumer> consumers = new ArrayList<Consumer>();
int n;
int maxSize;
public Broker(int maxSize) {
n = 0;
this.maxSize = maxSize;
}
synchronized void insert() throws InterruptedException {
// only here for testing don't want it to runaway and
//memory leak, only testing first 100 samples.
if (n == maxSize)
wait();
System.out.println("Producer: " + n++);
for (Consumer c : consumers) {
c.queue.add("Message " + n);
}
}
}
public static void main(String[] args) {
TestProducerConsumers pc = new TestProducerConsumers(100);
}
}

Categories