Earlier I posted a problem about implementing wait and notify, but I wasn't very clear, so here is a more specific question.
In the long code block below there is one wait and one notify. The notify is supposed to stop the wait and cause it to stop waiting. At the moment, i think the wait works, but the notify does not. Could someone explain why the notify doesn't notify the wait? Thanks!
Note: the rest of the code works i'm only interested in these two specific parts.
import com.fmr.ipgt.email.*;
import java.io.File;
import java.io.IOException;
import java.util.List;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import javax.mail.MessagingException;
class MyQuery {
synchronized void qQuery() throws Exception {
String query = ".z.k"; // The query that is used to query q; this can be changed here.
int version = 0;
c qConn = null;
qConn = new c(Main.host,Main.port); // Connect to the q database
while (Main.healthy) {
Object o = qConn.k(query); // Query q
version = c.t(o);
if(!(version==0)) {
System.out.println(version);
System.out.println("database healthy");
NewThread.suspendFlag = false;
notify();
break; // End the process if the database responds
}
}
System.out.println("reaches loop end");
}
}
class MyThread implements Runnable {
MyQuery myResource;
MyThread(String name, MyQuery so) {
myResource = so;
new Thread(this, name).start();
}
public void run() {
try {
myResource.qQuery(); // Begin a method to query q.
} catch (Exception e) {
e.printStackTrace();
}
}
}
class NewThread implements Runnable {
String name; // name of thread
Thread t;
static boolean suspendFlag;
private int minutes;
NewThread(int minutes) {
this.minutes = minutes;
System.out.println("reaches constructor");
t = new Thread(this);
suspendFlag = true;
t.start(); // Start the thread
}
// This is the entry point for thread.
public void run() {
try {
synchronized(this) {
while(suspendFlag) {
System.out.println("reaches wait");
wait(minutes*60000);
System.out.println("reaches end");
if(suspendFlag) {
Main.setHealth(false);
Main.sendMessages(); // The database has not responded for the given time. Report that it is unhealthy.
}
break;
}
}
} catch (InterruptedException e) {
System.out.println(name + " interrupted.");
} catch (MessagingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class Main {
private static String[] recipients;
private static String subject = "Database Failure";
private static String message = "The database has failed or is in a hung state";
private static String from;
static String host;
static int port;
private static String emails;
private static int minutes;
static boolean healthy = true;
public static void main(String args[]) throws Exception {
// Import information from the configuration file
SAXBuilder builder = new SAXBuilder();
File xmlFile = new File("/export/home/rhadm/file.xml"); // Note: The directory for the configuration file may need to be changed
try {
Document document = (Document) builder.build(xmlFile);
Element rootNode = document.getRootElement();
List list = rootNode.getChildren("parameters");
Element node = (Element) list.get(0);
host = node.getChildText("host");
port = Integer.parseInt(node.getChildText("port"));
emails = node.getChildText("emails");
String delims = "[ ]+";
recipients = emails.split(delims); // parse email list
minutes = Integer.parseInt(node.getChildText("time"));
from = node.getChildText("from");
} catch (IOException io) {
System.out.println(io.getMessage());
} catch (JDOMException jdomex) {
System.out.println(jdomex.getMessage());
}
MyQuery unhealthy = new MyQuery();
NewThread ob1 = new NewThread(minutes);
new MyThread("MyThread", unhealthy); // Create new Thread
}
public static void setHealth(boolean health){
System.out.println("database unhealthy");
healthy = health;
}
public static void sendMessages() throws MessagingException {
System.out.println("sending emails");
FCAPMailSender.postMail(recipients,subject,message,from);
}
}
You are synchronizing on different objects. The notify will only effect objects synchronized-waiting on the same object & instance.
The waiting thread is synchronized & waiting on a NewThread while the notifying thread is doing so on a MyQuery instance
Have a shared object.
private final Object LOCK = new Object();
synchronized(LOCK){
LOCK.wait();
}
synchronized(LOCK){
LOCK.notify();
}
Related
I'm trying to create a web crawler.
I've created a class to handle all URLs visited and to visit.
This class has to be accessed by multiple threads for retrieving and updating those lists.
The problem I'm facing, or at least I think, is in nextRandom() and probably also in next(). I think what is happening is the threads are interfering with each other since the function is somewhat synchronized but not atomic. Is there a way to make so this block of code is executed without any interruption by other threads?
The URL handler
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
public class UrlHandler {
private volatile Set<String> visited = new HashSet<String>();
private volatile List<String> toVisit = new ArrayList<String>();
public void addToVisit(String url) {
synchronized (this){
if (!visited.contains(url)) toVisit.add(url);
}
}
public void addToVisit(Collection<String> urls) {
synchronized (this){
for (String url : urls)
if (!visited.contains(url)) toVisit.add(url);
}
}
public void addVisited(String url){
synchronized (this){
visited.add(url);
}
}
public void addVisited(Collection<String> urls){
synchronized (this){
visited.addAll(urls);
}
}
public String next() {
while (toVisit.size() == 0) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized (this){
String url = toVisit.get(0);
toVisit.remove(0);
return url;
}
}
public String nextRandom() {
synchronized (this){
int n = 0;
if (toVisit.size() > 1){
n = ThreadLocalRandom.current().nextInt(toVisit.size());
}
String url = toVisit.get(n);
toVisit.remove(n);
return url;
}
}
public List<String> getToVisit() {
synchronized (this){
return toVisit;
}
}
public Set<String> getVisited() {
synchronized (this){
return visited;
}
}
}
Web Crawler
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class WebCrawler {
private final ExecutorService executor;
public WebCrawler(int nOfThreads) {
this.executor = Executors.newFixedThreadPool(nOfThreads);
}
public void add(Runnable runnable) {
this.executor.execute(runnable);
}
//Used to shut down safely and wait also 5 of seconds for not finished tasks
public void shutdown() {
this.executor.shutdown();
try {
this.executor.awaitTermination(5, TimeUnit.SECONDS);
if (!this.executor.isTerminated()) {
System.err.println("Timed out waiting for executor to terminate cleanly. Shutting down.");
this.executor.shutdownNow();
}
} catch (final InterruptedException e) {
System.err.println("Interrupted while waiting for executor shutdown.");
Thread.currentThread().interrupt();
}
}
}
Failing test example
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class UrlHandlerTest {
List<String> testList = new ArrayList<>(List.of("test1", "test2", "test3", "test3"));
List<String> uniqueTestList = new ArrayList<>(List.of("test1", "test2", "test3"));
UrlHandler urlHandler = new UrlHandler();
#Test
public void concurrentAccess(){
urlHandler.addToVisit(testList);
WebCrawler webCrawler = new WebCrawler(10);
for (int i = 0; i < urlHandler.getToVisit().size(); i++) {
webCrawler.add(new Runnable() {
#Override
public void run() {
String url = urlHandler.nextRandom();
urlHandler.addVisited(url);
System.out.println("Here thread " + Thread.currentThread().getId() + " working on: " + url);
}
});
}
webCrawler.shutdown();
System.out.println(urlHandler.getVisited());
assertEquals(true, urlHandler.getVisited().containsAll(uniqueTestList));
}
}
In the next method this code is a problem:
while (toVisit.size() == 0) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
The lock isn't held for this part, so size can be stale. Instead of this, try something like
while (toVisit.size() == 0)
wait();
Do this in a synchronized block so you have the lock held while checking the collection size. Code that adds to the collection should notify in order to wake up the waiting threads.
This piece of code is problematic:
for (int i = 0; i < urlHandler.getToVisit().size(); i++) {
webCrawler.add(new Runnable() {
// ...
});
}
The urlHandler.getToVisit().size() is always changing during the traversal, and there is uncertainty (because the size will be changed asynchronously).
Change to:
int size = urlHandler.getToVisit().size();
for (int i = 0; i < size; i++) {
webCrawler.add(new Runnable() {
// ...
});
}
I'm synchronizing and blocking on the same object. Each thread calls the testQueue() method in the PuppetShow class which instantiates a distinct object for each thread to block on. My problem is that once capacity==0, the first thread to encounter that condition calls wait() on its object and then the program hangs and no other thread runs. The third thread outputs "waaah" per the println statement and then no other lines are executed, despite the fact that I instantiate threads after this one.
How do I move past the lock.wait() line in the testQueue method in the PuppetShow() class?
I want to be able to block on distinct objects and add them to vectors in order to queue groups of threads. That's why I'm blocking on distinct objects and then adding these to a vector. To notify the thread I simply notify the element at a position in the vector.
import java.util.Vector;
public class PuppetShow {
private int numSeats = 2;
private int capacity = numSeats;
private Vector<Object> attendingPuppetShow = new Vector<Object>();
public Vector<Object> waitingStudents = new Vector<Object>();
public void testQueue() {
Object lock = new Object();
System.out.println("testQueue begin");
synchronized(lock) {
if(testAttending(lock)) {
try {
System.out.println("waaah");
lock.wait();
System.out.println("ugh");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public synchronized boolean testAttending(Object lock) {
System.out.println("testAttending");
boolean status;
if(capacity==0) {
waitingStudents.add(lock);
System.out.println("capacity="+capacity+" ws size="+waitingStudents.size());
status = true;
}
else {
capacity--;
attendingPuppetShow.add(lock);
System.out.println("capacity="+capacity+" aPS size="+attendingPuppetShow.size());
status = false;
}
return status;
}
public synchronized void testRelease() {
if(waitingStudents.size() > 0) {
while(waitingStudents.size() > 0) {
synchronized(waitingStudents.elementAt(0)) {
waitingStudents.elementAt(0).notify();
}
waitingStudents.removeElementAt(0);
capacity++;
}
}
}
}
class GreenStudent extends Thread {
private PuppetShow ps = new PuppetShow();
public GreenStudent(int id, PuppetShow ps) {
setName("GreenStudent-" + id);
this.ps = ps;
}
#Override
public void run() {
System.out.println(getName()+" queuing for show");
ps.testQueue();
}
}
class StaffMember extends Thread {
private PuppetShow ps = new PuppetShow();
public StaffMember(int id, PuppetShow ps) {
setName("StaffMember-" + id);
this.ps = ps;
}
#Override
public void run() {
ps.testRelease();
}
}
class Driver {
public static void main(String[] args) {
// TODO Auto-generated method stub
PuppetShow ps = new PuppetShow();
GreenStudent gs1 = new GreenStudent(1, ps);
GreenStudent gs2 = new GreenStudent(2, ps);
GreenStudent gs3 = new GreenStudent(3, ps);
StaffMember sm = new StaffMember(1,ps);
gs1.run();
gs2.run();
gs3.run();
sm.run();
}
}
gs1.run();
gs2.run();
gs3.run();
sm.run();
Needs to be
gs1.start();
gs2.start();
gs3.start();
sm.start();
In your example, run will be invoked by the calling thread (main thread). start will launch another thread then eventually call run.
This question already has answers here:
How do you kill a Thread in Java?
(17 answers)
Closed 9 years ago.
I'm with a headache on killing a thread with java ...
I saw a lot of topics on stackoverflow and i didnt get them working on my code ...
Can someone explain me how am i able to kill a thread without using deprecated function (like stop) and in a safe way please ( also my thread is running a socket: DatagramSocket).
Class p2p_app->
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.net.InetAddress;
//import java.net.UnknownHostException;
import java.util.LinkedList;
import java.util.Scanner;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class p2p_app {
private String ip;
private Integer porta;
private LinkedList<Vizinho> vizinhos;
private String pathSharedFolder;
private String pathBootStrap;
private int exit;
//private Thread send;
//private Thread receive;
private UDPreceive udpR;
public p2p_app(String args[]) throws IOException {
this.ip = InetAddress.getLocalHost().getHostAddress();
this.vizinhos = new LinkedList<Vizinho>();
this.exit = 0;
//this.send=null;
//this.receive=null;
this.udpR=null;
if(args.length==2){
this.pathSharedFolder=args[0];
this.pathBootStrap=args[1];
System.out.println(pathSharedFolder);
System.out.println(pathBootStrap);
}
else{
this.pathSharedFolder="./";
this.pathBootStrap="./p2p_bootstrap.conf";
System.out.println(pathSharedFolder);
System.out.println(pathBootStrap);
}
readFile(this.pathBootStrap);
createSharedFolder(this.pathSharedFolder);
}
public void assign(String tipo,String info) //tratar o file bootstrap.conf
{
Tipos currentTipos = Tipos.valueOf(tipo.toUpperCase());
switch(currentTipos){
case PATH: if(this.pathSharedFolder==null)
this.pathSharedFolder = info;
break;
case PORTA: this.porta = Integer.parseInt(info);
break;
case IP: StringTokenizer st = new StringTokenizer(info,":");
st.nextElement();
String[] tokens = info.split(":");
Vizinho s = new Vizinho(tokens[0],Integer.parseInt(tokens[1]));
this.vizinhos.add(s);
break;
default:
break;
}
}
public void trataLine(String line){
Pattern p = Pattern.compile("[\\w\\./:]+");
Matcher m = p.matcher(line);
String tipo = "";
while(m.find()){
if(tipo.compareTo("")==0)
tipo = m.group();
else assign(tipo,m.group());
}
}
public void readFile(String path) throws IOException{ //modifiquei este codigo para ver se existe ou nao o ficheiro bootstrap (VASCO)
String line;
Pattern p = Pattern.compile("\\$");
File f = new File(path);
if(f.exists()){
BufferedReader br;
br = new BufferedReader(new FileReader(path));
while ((line = br.readLine()) != null) {
Matcher m = p.matcher(line);
if(m.find() == true)
trataLine(line);
}
br.close();
}
else{
System.out.println("FILE :: BOOTSTRAP.CONF : Doesn't exist.");
}
}
public void createSharedFolder(String path) {
if(!(new File(path).exists()))
new File(path).mkdir();
}
public enum Tipos {
PATH,
PORTA,
T1,
T2,
T3,
R,
M,
K,
IP
}
public String getIp(){
return this.ip;
}
public Integer getPorta(){
return this.porta;
}
public int getExit(){
return this.exit;
}
public void setExit(int exit){
this.exit = exit;
}
public LinkedList<Vizinho> getVizinhos(){
LinkedList<Vizinho> aux = new LinkedList<Vizinho>();
for(Vizinho c : this.vizinhos) aux.add(c);
return aux;
}
public String toString(){
StringBuilder s = new StringBuilder();
s.append("IP:"+this.ip + "\n");
s.append("Porta:"+ this.porta +"\n");
s.append("Directory:" + this.pathSharedFolder + "\n");
s.append("-----Vizinhos-----");
for(Vizinho c : this.vizinhos)
s.append(c.toString());
return s.toString();
}
public void initThreads(p2p_app p2p){
//UDPreceive udpR = new UDPreceive(p2p);
this.udpR = new UDPreceive(p2p);
//UDPsend udpS = new UDPsend(p2p);
//this.receive = new Thread(udpR);
Thread t = new Thread(udpR);
//this.send = new Thread(udpS);
t.start();
//this.receive.start();
//this.send.start();
}
#SuppressWarnings("deprecation")
public void stopThreads(){
this.udpR.stopRun();
//this.receive.interrupt();
//this.receive.stop();
//this.receive.toString();
//this.send.interrupt();
//this.send.toString();
}
public void menu(){
System.out.println("1:Hello");
System.out.println("2:Vasco");
System.out.println("3:Exit");
}
public int choiceMenu(int i){
int numRowsInConsole = 60;
final String ESC = "\033[";
switch(i){
case 1:
System.out.println("FUNCIONOU HELLO");
System.out.print(ESC + "2J");
/*for (int ii=0; ii<numRowsInConsole; ii++) {
// scroll down one line
System.out.println("");
}*/
break;
case 2:
System.out.println("FUNCIONOU VASCO");
System.out.print(ESC + "2J");
break;
case 3:
i=-1;
System.out.print(ESC + "2J");
break;
default:
}
return i;
}
public static void main(String[] args) throws IOException {
int i;
p2p_app p2p = new p2p_app(args);
//p2p.initThreads(p2p);
System.out.println(p2p.toString());
Scanner sc = new Scanner(System.in);
while(p2p.getExit() != -1){
p2p.menu();
i = sc.nextInt();
p2p.setExit(p2p.choiceMenu(i));
System.out.println(p2p.getExit());
}
System.out.println("Woot woot!");
//p2p.stopThreads();
}
}
Classe UDPreceive->
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class UDPreceive implements Runnable {
private p2p_app p2p;
private DatagramPacket p;
public volatile boolean stopThread = true;
public void stopRun(){
this.stopThread=false;
}
public UDPreceive(p2p_app p2p){
this.p2p = p2p;
}
/**
* #param args
*/
public void run(){
DatagramSocket socket=null;
UDPpacket udp;
byte[] x = new byte[1000];
try{
socket = new DatagramSocket(8734);
socket.setBroadcast(true);
//while(this.p2p.getExit() !=-1){
while(stopThread){
p = new DatagramPacket(x,x.length);
socket.receive(p);
udp = new UDPpacket(p,this.p2p);
udp.tostring();
//udp.setDatagramPacket(p);
//String d = new String(p.getData());
//System.out.println("Mensagem enviada por mim: "+d);
}
//Thread.sleep(100);
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
how am i able to kill a thread on my main function in p2p_app class ? i create a thread for my UDPreceiver class :F
For the most part, the only "safe" way to kill a Thread is to code the Thread in such a way that it can receive a signal to stop. For example, use a boolean variable called shouldQuit and have the Thread periodically check that variable, quitting if it's true. You could also do stuff like interrupt the Thread, but that isn't always safe.
package test;
/**
* simple thread class that prints '.' to the screen
* #author Manex
*
*/
public class ThreadTest extends Thread {
private boolean running = true ;
public void run(){
try{
while(running){
//do something here
System.out.print(".");
sleep(1000);
}
}catch(InterruptedException e){
System.out.println(e.getMessage());
}
System.out.println("Stopped");
}
/**
* a method to stop the thread
*/
public void stopRunning(){
this.running = false ;
}
public static void main(String[] args){
//creating threads
ThreadTest[] t = new ThreadTest[2] ;
t[0] = new ThreadTest() ;
t[1] = new ThreadTest() ;
//starting threads
for(ThreadTest e : t){
e.start();
}
try {
//the main thread does something
int x = 5 ;
while(x > 0){
sleep(1000) ;
x -= 1 ;
}
//the main thread ended
System.out.println("main thread ends here");
} catch (InterruptedException e) {
e.printStackTrace();
}
//before exiting - stop all threads
for(ThreadTest e : t){
e.stopRunning();
}
}
}
if ur planing on stopping threads that you have created , for any reason , you should keep tracking them and hold a reference to each thread you might want to stop instead of waiting for it to done execution all by itself (the run method simply ends).
in this simple test , if you remove the stop loop , the threads will continue printing and never stop untill you stop them manually , even after main thread termination..
i hope this was usefull..
The reason your UDPReceive thread is not stopping is you are using the blocking method DatagramSocket.receive() in your UDPReceive.run() while loop. The JavaDocs for this method say: "This method blocks until a datagram is received." By blocks it means never, ever returns. So the thread with the receive() is still running when you want your program to exit. It is a "hung thread" and the only way to relieve it is to kill the entire process, such as Ctrl+C.
To fix it, call socket.setSoTimeout() before your UDPReceive.run() while loop starts. This will make the final call to receive() timeout and actually complete. Then catch the SocketTimeoutException that will occur if your socket times out (e.g. at the end of your program when the thread completes, or earlier if you have an actual timeout error condition) and handle the exception appropriately (e.g. if stopThread is triggered just ignore the exception, or if stopThread is not yet triggered log it as a warning). Example:
public void run(){
DatagramSocket socket=null;
UDPpacket udp;
byte[] x = new byte[1000];
try{
socket = new DatagramSocket(8734);
socket.setBroadcast(true);
socket.setSoTimeout(20*1000); // 20 seconds
//while(this.p2p.getExit() !=-1){
while(stopThread){
p = new DatagramPacket(x,x.length);
try {
socket.receive(p);
} catch (SocketTimeoutException e) {
if (stopThread){
System.err.println("Warning: socket timed out " +
"before program completed: " + e.getLocalizedMessage());
} else {
// program completed, so just ignore and move on
break;
}
}
udp = new UDPpacket(p,this.p2p);
udp.tostring();
//udp.setDatagramPacket(p);
//String d = new String(p.getData());
//System.out.println("Mensagem enviada por mim: "+d);
}
//Thread.sleep(100);
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
This should do the trick. The stopThread logic itself looks fine (although I would rename the boolean to continueThread, because you're stopping when it is false).
Finally , i did it !
The result was a little different from what you guys said,
I'll post my answer in case if anyone will ask it !
The solution was to send a DatagramPacket to myself ! :)
Class udpReceiver ->
//package testeThread;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
public class udpReceiver implements Runnable {
public volatile boolean stopThread = true;
private DatagramSocket socket;
//private DatagramSocket socket;
public udpReceiver() {
// TODO Auto-generated constructor stub
//this.socket = socket;
}
public void stopRun(){
synchronized(this){
this.stopThread=false;
byte[] x = new byte[1000];
try{
DatagramPacket p = new DatagramPacket(x,x.length,InetAddress.getLocalHost(),8737);
this.socket.send(p);
} catch(UnknownHostException e){
e.printStackTrace();
} catch(IOException e){
e.printStackTrace();
}
}
}
/**
* #param args
*/
public void run(){
//DatagramSocket socket=null;
DatagramPacket p = null;
//byte[] x = new byte[1000];
try{
this.socket = new DatagramSocket(8737);
this.socket.setBroadcast(true);
}catch(SocketException e){
e.printStackTrace();
}
//socket.setSoTimeout(5*1000); // 20 seconds
while(stopThread){
byte[] x = new byte[1000];
p = new DatagramPacket(x,x.length);
try{
this.socket.receive(p);
}catch(IOException e){
e.printStackTrace();
}
String d = new String(p.getData());
System.out.println("Mensagem enviada por mim: "+d);
}
this.socket.close();
/* try{
socket = new DatagramSocket(8735);
socket.setBroadcast(true);
//socket.setSoTimeout(5*1000); // 20 seconds
while(stopThread){
byte[] x = new byte[1000];
p = new DatagramPacket(x,x.length);
try {
socket.receive(p);
} catch (SocketTimeoutException e) {
if (stopThread){
//System.err.println("Warning: socket timed out before program completed: " + e.getLocalizedMessage());
} else {
// program completed, so just ignore and move on
break;
}
}
String d = new String(p.getData());
//System.out.println("Mensagem enviada por mim: "+d);
//System.out.println("SOCKET CLOSE"+socket.isConnected());
}
//socket.setSoTimeout(1000);
socket.close();
System.out.println("SOCKET CLOSE"+socket.isConnected());
} catch (SocketException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException io){
io.printStackTrace();
}*/
/*catch (SocketTimeoutException soc){
if(this.stopThread == false) {
this.stopThread = false;
}
soc.printStackTrace();
}*/
}
}
Class Servidor->
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.Scanner;
//package testeThread;
public class Servidor {
private int exit;
public Servidor() {
// TODO Auto-generated constructor stub
}
public int getExit(){
return this.exit;
}
public void setExit(int exit){
this.exit = exit;
}
public int choiceMenu(int i){
int numRowsInConsole = 60;
final String ESC = "\033[";
switch(i){
case 1:
System.out.println("FUNCIONOU HELLO");
System.out.print(ESC + "2J");
/*for (int ii=0; ii<numRowsInConsole; ii++) {
// scroll down one line
System.out.println("");
}*/
break;
case 2:
System.out.println("FUNCIONOU VASCO");
System.out.print(ESC + "2J");
break;
case 3:
i=-1;
System.out.print(ESC + "2J");
break;
default:
}
return i;
}
public void menu(){
System.out.println("1:Hello");
System.out.println("2:");
System.out.println("3:Exit");
}
#SuppressWarnings("deprecation")
public static void main(String[] args) {
int i;
Servidor s = new Servidor();
//try{
//DatagramSocket socket = new DatagramSocket(8735);
udpReceiver udpR = new udpReceiver();
Thread t = new Thread(udpR);
t.start();
Scanner sc = new Scanner(System.in);
while(s.getExit() != -1){
s.menu();
i = sc.nextInt();
s.setExit(s.choiceMenu(i));
System.out.println(s.getExit());
}
//DatagramSocket socket = new DatagramSocket(8735);
//socket.close();
//t.interrupt();
udpR.stopRun();
try{
t.join();
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println("MAIN FIM");
//t.stop();
/*}catch(SocketException e){
e.printStackTrace();
}*/
}
}
P.S: that version isn't the same as the one upstairs ... But i get the same logic as i wrote the other one , and now it works good ! I can quit the program without using CTRL+C and it can receives the message now ! :)
I have a class Producer and a class Printer.
The producers read from a file data to create PrinttJobs objects.
A Producer generates one PrintJob and add to a Queue, notifying the Printer. Producer than waits 1 - 5 seconds to create new PrintJobs.
When the Printer is notyfied it turns on and get the jobs from the queue and print them. In this period Producer can't work. Printer prints everything and wait again, letting the Producer work again.
The app works with 2 Producers and 1 Printer.
My problem is that sometimes it go well, sometimes it doens't print produce everything. Also I think that my wait with the time limit 1-5 seconds is not working well/ may be the problem. Code is below:
EDITED
When the Producers actually produce something, they send at the same time almost always. And sometimes it stop producing but still data in the file.
class Printer implements Runnable {
protected long MILLIS_PER_PAGE = 500;
private String name;
Queue queue;
boolean lock = false;
public Printer(String name, Queue queue) {
this.name = name;
this.queue = queue;
}
public String getPrinterName() {
return name;
}
#Override
public void run() {
System.out.println("["+getPrinterName()+"] Ligando...");
while(true) {
synchronized(this){
if(queue.isEmpty()) {
try {
System.out.println("["+getPrinterName()+"] Esperando por tabalho de impressão...");
lock = false;
halt();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
else {
lock = true;
PrintJob pj = queue.removeFront();
System.out.println("Imprimindo "+ pj.getJobName());
try {
wait(pj.getNumberOfPages() * MILLIS_PER_PAGE);
System.out.println(pj.getJobName() + " ok.");
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public void halt() throws InterruptedException {
wait();
}
}
`
`
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Scanner;
class Producer implements Runnable {
private String name;
Queue queue;
String job;
int pags;
String arquivo;
public Producer(String name, Queue queue, String arquivo) {
this.name = name;
this.queue = queue;
this.arquivo = arquivo;
}
public String getProducerName() {
return name;
}
#Override
public void run(){
synchronized (PrinterApp.printer) {
FileReader fin;
try {
fin = new FileReader(arquivo);
Scanner src = new Scanner(fin);
while (src.hasNext() ) {
if (PrinterApp.printer.lock == true){
PrinterApp.printer.wait();
}
job = src.next();
pags = src.nextInt();
PrintJob p = new PrintJob(job, pags);
queue.addBack(p);
System.out.println("["+getProducerName()+"] produzindo arquivo " + job +", número de páginas: " + pags);
PrinterApp.printer.notify();
PrinterApp.printer.wait(1000 + (int)Math.round((Math.random() * (5000 - 1000))));
}
fin.close();
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (QueueException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
The problem is with the following
if (PrinterApp.printer.lock == true){
PrinterApp.printer.wait();
}
lock may not be true after wait ends. Waits should always be in a loop.
Also the printer never notifies the producers that lock has changed. You should call notify before calling wait in the printer.
If this isn't for isn't homework, then I'd recommend using a blocking queue which will handle all the waits and notifies for you.
class Printer implements Runnable {
protected long MILLIS_PER_PAGE = 500;
private String name;
Queue queue;
boolean lock = false;
public Printer(String name, Queue queue) {
this.name = name;
this.queue = queue;
}
public String getPrinterName() {
return name;
}
#Override
public void run() {
System.out.println("["+getPrinterName()+"] Ligando...");
while(true) {
synchronized(this){
if(queue.isEmpty()) {
try {
System.out.println("["+getPrinterName()+"] Esperando por tabalho de impressão...");
lock = false;
notifyAll();
halt();
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
else {
lock = true;
PrintJob pj = queue.removeFront();
System.out.println("Imprimindo "+ pj.getJobName());
try {
wait(pj.getNumberOfPages() * MILLIS_PER_PAGE);
System.out.println(pj.getJobName() + " ok.");
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public void halt() throws InterruptedException {
wait();
}
}
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Scanner;
class Producer implements Runnable {
private String name;
Queue queue;
String job;
int pags;
String arquivo;
public Producer(String name, Queue queue, String arquivo) {
this.name = name;
this.queue = queue;
this.arquivo = arquivo;
}
public String getProducerName() {
return name;
}
#Override
public void run(){
FileReader fin;
try {
fin = new FileReader(arquivo);
Scanner src = new Scanner(fin);
while (src.hasNext() ) {
synchronized (PrinterApp.printer) {
while (PrinterApp.printer.lock == true){
PrinterApp.printer.wait();
}
job = src.next();
pags = src.nextInt();
PrintJob p = new PrintJob(job, pags);
queue.addBack(p);
System.out.println("["+getProducerName()+"] produzindo arquivo " + job +", número de páginas: " + pags);
PrinterApp.printer.notifyAll();
}
// don't wait here since your not waiting on a condition to change
Thread.sleep(1000 + (int)Math.round((Math.random() * (5000 - 1000))));
}
fin.close();
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (QueueException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
I tried to write a file monitor which will check the file if a new line is appended,the monitor in fact is a thread which will read the line by a randomaccessfile all the time.
This is the monitor core codes:
public class Monitor {
public static Logger log = Logger.getLogger(Monitor.class);
public static final Monitor instance = new Monitor();
private static final ArrayList<Listener> registers = new ArrayList<Listener>();
private Runnable task = new MonitorTask();
private Thread monitorThread = new Thread(task);
private boolean beStart = true;
private static RandomAccessFile raf = null;
private File monitoredFile = null;
private long lastPos;
public void register(File f, Listener listener) {
this.monitoredFile = f;
registers.add(listener);
monitorThread.start();
}
public void replaceFile(File newFileToBeMonitored) {
this.monitoredFile = newFileToBeMonitored;
// here,how to restart the monitorThread?
}
private void setRandomFile() {
if (!monitoredFile.exists()) {
log.warn("File [" + monitoredFile.getAbsolutePath()
+ "] not exist,will try again after 30 seconds");
try {
Thread.sleep(30 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
setRandomFile();
return;
}
try {
if (raf != null) {
raf.close();
lastPos = 0;
}
raf = new RandomAccessFile(monitoredFile, "r");
log.info("monitor file " + monitoredFile.getAbsolutePath());
} catch (FileNotFoundException e) {
// The file must exist now
} catch (IOException e) {}
}
private void startRead() {
beStart = true;
String line;
while (beStart) {
try {
raf.seek(lastPos);
while ((line = raf.readLine()) != null) {
fireEvent(new FileEvent(monitoredFile.getAbsolutePath(),
line));
}
lastPos = raf.getFilePointer();
} catch (IOException e1) {}
}
}
private void stopRead() {
this.beStart = false;
}
private void fireEvent(FileEvent event) {
for (Listener lis : registers) {
lis.lineAppended(event);
}
}
private class MonitorTask implements Runnable {
#Override
public void run() {
stopRead();
//why putting the resetReandomAccessFile in this thread method is that it will sleep if the file not exist.
setRandomFile();
startRead();
}
}
}
This is some help classes:
public interface Listener {
void lineAppended(FileEvent event);
}
public class FileEvent {
private String line;
private String source;
public FileEvent(String filepath, String addedLine) {
this.line = addedLine;
this.source = filepath;
}
//getter and setter
}
And this is a example to call the monitor:
public class Client implements Listener {
private static File f = new File("D:/ab.txt");
public static void main(String[] args) {
Monitor.instance.register(f, new Client());
System.out.println(" I am done in the main method");
try {
Thread.sleep(5000);
Monitor.instance.replaceFile(new File("D:/new.txt"));
} catch (InterruptedException e) {
System.out.println(e.getMessage());
}
}
#Override
public void lineAppended(FileEvent event) {
String line = event.getLine();
if (line.length() <= 0)
return;
System.err.println("found in listener:" + line + ":" + line.length());
}
}
Now,my probelm is the code work well if I just call:
Monitor.instance.register(file,listener);
This will monitor the file for line appending,and will notify the listener.
However it does not work when I call the :
Monitor.instance.replaceFile(anotherfile);
This means I want to monitor another file rather than before.
So in my Monitor I have to restart the thread,how to make it?
I have tried the:
monitorThread.interruppt();
It does not wrok.
Anyone can fix it for me or tell me how to do ?
Thanks.
Before I ask,I have googling the "restart java thread",so I know one can not restart a dead thread,but my thread does not return,so I think it can be restarted.
You don't restart a Thread, instead you create a new one each time you want to start a thread.
A better alternative may be to use Executors.newCachedThreadPool() which gives you a pool of thread which will be started/recycle for you.
BTW: You are using recursion rather than a loop to poll if the file exists. Using recursion can mean if you wait too long it will throw a StackOverflowError. IMHO you shouldn't wait at all, the polling thread should repeatedly attempt to open the file until it is told to stop (or the file appears)
Your current implementation also means if the file is replaced, you will have to reopen the file in the background thread anyway.
Instead of explaining, I just coded up a skeleton example. I did not test it terribly well, but it may be of some use.
In order to monitor a(nother) file, just create a new Monitor, passing it a ScheduledExecutorService. Starting and stopping monitoring is straightforward. You can (should) reuse the same executor for multiple monitors.
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public interface Event
{
}
public interface Listener
{
void handle(Event event);
}
public class Monitor
{
private static final int CHECK_EVERY_SECONDS = 10;
private static final int RECHECK_AFTER_IF_NOT_EXISTS_SECONDS = 30;
private File file;
private ScheduledExecutorService executor;
private boolean active;
private List<Listener> listeners;
public Monitor(File file, ScheduledExecutorService executor)
{
super();
this.file = file;
this.executor = executor;
listeners = new ArrayList<Listener>();
}
public synchronized void start()
{
if (active)
{
return;
}
active = true;
executor.execute(new Runnable()
{
public void run()
{
synchronized (Monitor.this)
{
if (!active)
{
System.out.println("not active");
return;
}
}
if (!file.exists())
{
System.out.println("does not exist, rescheduled");
executor.schedule(this, RECHECK_AFTER_IF_NOT_EXISTS_SECONDS, TimeUnit.SECONDS);
return;
}
Event event = doStuff(file);
System.out.println("generated " + event);
updateListeners(event);
System.out.println("updated listeners and rescheduled");
executor.schedule(this, CHECK_EVERY_SECONDS, TimeUnit.SECONDS);
}
});
}
private Event doStuff(final File file)
{
return new Event()
{
public String toString()
{
return "event for " + file;
}
};
}
public synchronized void stop()
{
active = false;
}
public void addListener(Listener listener)
{
synchronized (listeners)
{
listeners.add(listener);
}
}
public void removeListener(Listener listener)
{
synchronized (listeners)
{
listeners.remove(listener);
}
}
private void updateListeners(Event event)
{
synchronized (listeners)
{
for (Listener listener : listeners)
{
listener.handle(event);
}
}
}
public static void main(String[] args) throws IOException
{
ScheduledExecutorService executor = Executors.newScheduledThreadPool(4);
File file = new File("test.png");
Monitor monitor = new Monitor(file, executor);
monitor.addListener(new Listener()
{
public void handle(Event event)
{
System.out.println("handling " + event);
}
});
monitor.start();
System.out.println("started...");
System.in.read();
monitor.stop();
System.out.println("done");
executor.shutdown();
}
}
See this post How to start/stop/restart a thread in Java?
I assume you answered your question
one can not restart a dead thread
This link may be helpful to you How to restart thread in java?
A thread in Java cannot be re-started. Every time you need to restart the thread you must make a new one.
That said, you might want to look at:
private void setRandomFile() {
if (!monitoredFile.exists()) {
log.warn("File [" + monitoredFile.getAbsolutePath()
+ "] not exist,will try again after 30 seconds");
try {
Thread.sleep(30 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
setRandomFile();
return;
}
// ....
}
Here you sleep for 30 seconds if the file does not exist, then recursively call the same function. Now, I don't know what business requirements you have, but if this recursion ran long enough you will run out of stack space. Perhaps you will be better served with a while loop or even better, a little synchronisation like a Semaphore.