I'm working on compiling a bunch of tweets for an information retrieval class. I'm trying this using both the REST API and the Streaming API through twitter4j. When using the Streaming API, I use the following modifications to this example:
final LimitedFileWriter output = new LimitedFileWriter("Tweets","tweets");
TwitterStream twitterStream = new TwitterStreamFactory(cb.build()).getInstance();
StatusListener listener = new StatusListener() {
#Override
public void onStatus(Status status) {
try{
output.write("#" + status.getUser().getScreenName() + " -- " + status.getText()+"\n");
}
catch(IOException e){
e.printStackTrace();
}
}
}
twitterStream.addListener(listener);
twitterStream.sample("en");
//output.close();
It seems I can't ever close my writer. The writer I am using simply wraps BufferedWriter, while keeping track of file size. If the file exceeds a certain size (128MB), the writer will close the current file and create a new file. Here are the relevant class functions:
public void write(String s) throws IOException
{
if(bytesWritten + s.getBytes(charset).length >= MAXSIZE){
output.close();
bytesWritten = 0;
fileNum++;
String fileName = directory + "/" + baseName+fmt.format(fileNum);
currentFile = new File(fileName);
output = new BufferedWriter
(new OutputStreamWriter(new FileOutputStream(fileName),charset));
}
output.write(s);
bytesWritten += s.getBytes(charset).length;
}
public void close() throws IOException{
output.close();
}
If I try to close the writer after twitterStream.sample() (commented out), the program crashes because I am trying to write to a closed file. If my understanding is correct, this is because the TwitterStream class creates a new thread which runs concurrently with the main thread. Then, the main thread closes the stream and the twitterStream can no longer write to it.
If that's the case, where should I close my writer?
If I have understood your question correctly, you want to be able to turn of the tweets collection at some point, close your open file writers and have a clean exit. To achieve it you can use a synchronized block.
final Object lock = new Object();
final LimitedFileWriter output = new LimitedFileWriter("Tweets","tweets");
TwitterStream twitterStream = new TwitterStreamFactory(cb.build()).getInstance();
StatusListener listener = new StatusListener() {
#Override
public void onStatus(Status status) {
try{
output.write("#" + status.getUser().getScreenName() + " -- " + status.getText()+"\n");
// free the lock
if (some_condition_like_I_have_enough_files) {
synchronized (lock) {
lock.notify();
}
}
catch(IOException e){
e.printStackTrace();
}
}
}
twitterStream.addListener(listener);
twitterStream.sample("en");
try {
synchronized (lock) {
lock.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
// close the twitterstream
// close the writer
Related
#FXML
private TextArea textarea;
#FXML
private ImageView imagev;
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
Serverth Server = new Serverth();
Server.start();
}
class Serverth extends Thread {
#Override
public void run() {
try {
final int NUM_THREAD = 99;
ServerSocket socket = new ServerSocket(8078);
ExecutorService exec = Executors.newFixedThreadPool(NUM_THREAD);
System.out.println("SERVER SOCKET CREATED");
while (!isInterrupted()) {
Socket in = socket.accept();
Runnable r = new ThreadedHandler(in);
exec.execute(r);
}
} catch (IOException e) {
System.out.println(e.getMessage());
}
}
}
class ThreadedHandler implements Runnable {
private Socket incoming;
public ThreadedHandler(Socket in) {
incoming = in;
}
public void run() {
try {
try {
ObjectInputStream is=new ObjectInputStream(incoming.getInputStream());
while(true) {
if (is.available() > 0) {
String line = is.readUTF();
textarea.appendText("\n" + "[" + new java.util.Date() + "] : " + line);
if (line.contains("inviato")) {
Object obj = is.readObject();
Email ema = (Email) obj;
try {
SimpleDateFormat formatter = new SimpleDateFormat("dd-M-yyyy-hh-mm-ss");
FileOutputStream fileOut = new FileOutputStream("src/Server/" + ((Email) obj).getDestinat() + "/" + formatter.format(((Email) obj).getData()) + ".txt");
ObjectOutputStream objectOut = new ObjectOutputStream(fileOut);
objectOut.writeObject(ema);
objectOut.flush();
objectOut.close();
System.out.println("The Object was succesfully written to a file");
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
}
} catch(IOException ex) {
ex.printStackTrace();
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
incoming.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
Inside the run method (in Serveth class), I create a server socket and call exec.execute method.
Inside the run method (in ThreadedHandler class), the server is waiting for messages from the client (in this specific case, it creates a new .txt file but it is not important).
Everything works but causes excessive use of the CPU and lag!!!
InputSteam.available method returns a value instantly, telling you no bytes are available to be read, so this code runs a very "hot" spin loop:
while(true) {
if (is.available() > 0) {
...
}
}
The available method is rarely useful and often gives confusing results (see for example inputstream.available() is 0 always). I would suggest you get rid of the if statement altogether:
while(true) {
String line = is.readUTF();
textarea.appendText("\n" + "[" + new java.util.Date() + "] : " + line);
...
}
There's no way for this your code to exit the loop normally. You may want to add a mechanism for the client to disconnect from the server.
I am using a ExecutorService to have multiple threads writing text into a file, but i cannot manage to synchronize the run() method and instead of having the proper line by line String i ask, i have a mixup of all the characters of the Strings because they write it at the same time.
import java.io.BufferedReader
...
class WriteDns implements Runnable {
File file;
String text;
WriteDns(File file, String text) {
this.file = file;
this.text = text;
}
public void run() {
synchronized (this) {
try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(file)))) {
bw.write(turnDns() + "\n");
} catch (IOException e) {
System.out.println("Error");
}
}
}
public String turnDns() {
int space = text.indexOf(' ');
String ip = text.substring(0, space);
String theRest = text.substring(space);
String temp = ip;
try {
ip = InetAddress.getByName(ip).getHostName();
if (ip == temp)
return "NotFound " + theRest;
return ip + " " + theRest;
} catch (UnknownHostException e) {
System.out.println("Error in change");
return "-changeErr " + theRest;
}
}
}
public class Main00 {
static File oldFile = new File("oldfile.txt");
public static void main(String[] args) {
readLines();
}
public static void readLines() {
try (BufferedReader br = new BufferedReader(new FileReader(oldFile))) {
File f = new File("file.txt");
ExecutorService service = Executors.newFixedThreadPool(10);
for (String t = br.readLine(); t != null; t = br.readLine()) {
service.execute(new WriteDns(f, t));
}
service.shutdown();
} catch (IOException e) {
e.printStackTrace();
}
}
}
You're synchronising on this but you're making a new instance of your thread worker for every thread, so each thread is locking on itself and never waiting for any other threads. You need to lock on an object that is visible to all threads, perhaps a static object or pass in a lock object when you instantiate your WriteDns.
With that said, having multiple threads open on one file is inherently prone to problems like you're experiencing, and you gain nothing from multiple threads writing since your bottleneck is your storage medium and not your processor. You should rather have multiple threads providing information/data to one dedicated writer thread that has exclusive access to the file you want to write to, as #FlorianSchaetz suggested.
I want to implement my own logger that write logs in file. It could be run from many threads and an issue is how to synchronized access to log file.
private synchronized static void writeToFile(String tag, String msg,
Throwable tr, Context ctx) {
try {
String s = System.getProperty("line.separator");
File f = Environment.getExternalStorageDirectory();
Log.i(TAG, "Path to app " + f.getAbsolutePath());
File l = new File(f, "log.txt");
if (!l.exists()) {
l.createNewFile();
}
String e = Log.getStackTraceString(tr);
StringBuilder b = new StringBuilder();
b.append(HttpCommand.getDateForUrl(System.currentTimeMillis()));
b.append(tag);
b.append(msg);
b.append(e);
b.append(s);
OutputStream out = new FileOutputStream(l);
out.write(b.toString().getBytes());
out.flush();
out.close();
} catch (IOException e) {
Log.e(TAG, "Failed to create backup");
}
}
Is it enough to sync access to database with sync by class if I pass it in different threads?
synchronized(X.class) {
writeTiFile()
}
Since your writeToFile() function is synchronized, you don't have to wrap any calls to it with the synchronized {} block.
See here for more info:
http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html
You can use ConcurrentLinkedQueue, put all messages to Queue and create thread that take from queue and write it to file.
i've a java servlet that makes some reports. When a user choose a report it makes a query on a db and stream the xls report to the client. All in synchronous way. The problem is that sometimes i've a lot of records to fetch from the db and i would like to give a better user experience, allowing the user to do something else while the report is processing and popping out in some way the link when the process is finished. Is there a java library or some techniques to avoid the long waiting and achieve that goal?
Right now i've prepared a piece of code that in a asynchronous way completes the report and sends an email to the registered client, with the url from wich download the file, but it has to be replaced with something else because i can no longer communicate by email.
Thanks in advance
heres my take on this, i dont know of a single library that will exactly match you needs, youd probably need some custom development here.
I believe you have implemented async service that on completion sends
out an email for notification. Instead of sending out an email, let
that thread update a job table of some sort -- an entry in a db table
or some application/session scoped map.
Have a servlet/restful ws
expose that job table at some url. Poll the url at regular
intervals. Ajax poll is a standard feature in js libraries JQuery,
Prototype.
When you get a response that some report is complete, show
some popup or may be a facebook you-have-notification kind of thing
on the client side.
i have not considered authentication/authorization issues here, you need to take care of that as well.
Hope this helps
A multithreaded client server program to download my image files.
Since there are four files to download the client makes 4 connection attempts. This is not limited to 4 but the files sent by the FileServer will get repeated after the fourth attempt. The save dialog and file saving is done in different threads so as to not hamper the file downloading.
Here is the FileServer...
public class FileServer {
private final ExecutorService exec = Executors.newCachedThreadPool();
final String[] fileNames = {
"C:\\Users\\clobo\\Pictures\\Arpeggios\\Ex 1.jpg",
"C:\\Users\\clobo\\Pictures\\Arpeggios\\Ex 2.jpg",
"C:\\Users\\clobo\\Pictures\\Arpeggios\\Ex 3.jpg",
"C:\\Users\\clobo\\Pictures\\Arpeggios\\Ex 4.jpg"
};
public void start() throws IOException {
ServerSocket socket = new ServerSocket(7777);
System.out.println("Waiting for client message...");
while (!exec.isShutdown()) {
try {
for (final String fileName : fileNames){
final Socket conn = socket.accept();
exec.execute(new Runnable() {
public void run() {
sendFile(conn,fileName);
}
});
}
} catch (RejectedExecutionException e) {
if (!exec.isShutdown())
log("task submission rejected", e);
}
}
}
public void stop() {
System.out.println("Shutting down server...");
exec.shutdown();
}
private void log(String msg, Exception e) {
Logger.getAnonymousLogger().log(Level.WARNING, msg, e);
}
public void sendFile(Socket conn, String fileName) {
File myFile = new File(fileName);
if (!myFile.exists()) {
log("File does not exist!",null);
}
// file does exist
System.out.println(Thread.currentThread().getName());
System.out.println("AbsolutePath:" + myFile.getAbsolutePath());
System.out.println("length: " + myFile.length());
if (myFile.exists()) {
try {
ObjectOutputStream oos = new ObjectOutputStream(
conn.getOutputStream());
oos.writeObject(myFile);
oos.close();
} catch (IOException e) {
log("IOException Error", e);
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException {
FileServer fs = new FileServer();
fs.start();
}
}
here is the FileServerClient...
public class FileServerClient {
private final ExecutorService exec = Executors.newCachedThreadPool();
Frame myFrame = new Frame();
List<File> fileList = new ArrayList<File>();
public void receiveFileFromServer() throws Exception{
Socket sock = null;
InputStream socketInputStream = null;
String host = "localhost";
int port = 7777;
for (int i=0;i<4;i++) {
sock = new Socket(host, port);
socketInputStream = sock.getInputStream();
System.out.println("Connection successful...");
// recieve the file
ObjectInputStream ois = new ObjectInputStream(socketInputStream);
// file from server is deserialized
final File myfile = (File) ois.readObject();
fileList.add(myfile);
// deserialized file properties
System.out.println("AbsolutePath: " + myfile.getAbsolutePath());
System.out.println("FileName:" + myfile.getName());
System.out.println("length" + myfile.length());
exec.execute(new Runnable() {
public void run() {
saveFile(myfile);
}
});
}
}
private void saveFile(File myfile) {
FileDialog fileDialog = new FileDialog(myFrame,
"Choose Destination for "+ myfile.getName(), FileDialog.SAVE);
fileDialog.setDirectory(null);
fileDialog.setFile("enter file name here");
fileDialog.setVisible(true);
String targetFileName = fileDialog.getDirectory()
+ fileDialog.getFile() + ".jpg";
System.out.println("File will be saved to: " + targetFileName);
copyBytes(myfile, targetFileName);
}
private void copyBytes(File originalFile, String targetFileName) {
try {
FileInputStream in = new FileInputStream(originalFile);
FileOutputStream out = new FileOutputStream(targetFileName);
int c;
while ((c = in.read()) != -1) {
out.write(c);
}
out.close();
in.close();
} catch (Exception e) {
log("IOException Error", e);
}
}
private void log(String msg, Exception e) {
Logger.getAnonymousLogger().log(Level.WARNING, msg, e);
}
public static void main(String[] args) throws Exception {
FileServerClient client = new FileServerClient();
client.receiveFileFromServer();
}
}
You could make an asynchronous request from the client. Lets assume that you client is an html page. When the user selects a report and clicks on 'submit' you could fire an ajax request with the report parameters (jquery can be useful for this). It would be good to keep a section on the user homepage that says something like 'prepared reports'. The client can then goto the prepared report section to download the report. As specified in the comments above, you may also have to implement a popup that informs the user that the requested report is ready. the popup is shown when the ajax requests returns successfully. However, the client may have logged out by the time the report finishes, so it may be a good idea to make the download link available again in the 'prepared reports' section when the user logs in.
I have several threads which need to write to two different text files. So far I have this code:
public class Logger {
public static void printToGameLog(String value){
Writer writer = null;
try {
writer = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream("GameLog.txt", true), "utf-8"));
synchronized(writer){
writer.write(outputString + "\r\n");
}
} catch (IOException ex){
System.out.println("cannot create log file");
}
}
public static void printToServerLog(String value){
Writer writer = null;
try {
writer = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream("serverLog.txt", true), "utf-8"));
synchronized(writer){
writer.write(outputString + "\r\n");
}
} catch (IOException ex){
System.out.println("cannot create log file");
}
}
}
Is this an acceptable way of ensuring no more than one thread is writing to the same file at the same time?
If a thread calls one of these methods and enters the sync block, then what happens if another thread comes along and tries to execute the same method. When it tries to use the local variable writer, will it try and obtain the same object that has been locked by the other thread and therefore block? I would have thought that it would simply create its own separate variable, which would mean I should make writer a static class variable instead?
Since there are separate log files, I don't see why you need to have class-level synchronization. Seems like a needless bottleneck. I'd provide sync for each method separately (since it's fine for them to hit separate files simultaneously):
public class Logger
{
private static final Object GAME_LOG_LOCK = new Object();
private static final Object SERVER_LOG_LOCK = new Object();
public static void printToGameLog(String value){
synchronized (GAME_LOG_LOCK) {
Writer writer = null;
try {
writer = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream("GameLog.txt", true), "utf-8"));
writer.write(outputString + "\r\n");
} catch (IOException ex){
System.out.println("cannot create log file");
}
}
}
public static void printToServerLog(String value){
synchronized (SERVER_LOG_LOCK) {
Writer writer = null;
try {
writer = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream("serverLog.txt", true), "utf-8"));
writer.write(outputString + "\r\n");
} catch (IOException ex){
System.out.println("cannot create log file");
}
}
}
}
That's a null pointer exception in your code, try this way of using the synchronized block on a static method
synchronized(Logger.class){
or another alternative is to set the whole methods synchronized, like this
public static synchronized void printToGameLog(String value){
and
public static synchronized void printToServerLog(String value){
I'm not convinced that you need synchronization in here, you only need synchronization if you have a state that is being read/written from multiple threads.
Here is another take on your problem. It uses a single thread to write the log file and only this thread has access to the files. The threads that have to log something write against a BlockingQueue:
public class ThreadedLog {
//This is some code to test the logger
public static void main(String[] args) throws UnsupportedEncodingException, FileNotFoundException {
ThreadedLog log = new ThreadedLog("/tmp/test.txt");
// Start 100 thread that write against the log
for (int i = 0; i < 100; i++) {
new Thread(new TestLogger(log)).start();
}
}
private static class TestLogger implements Runnable {
private ThreadedLog log;
public TestLogger(ThreadedLog log) {
this.log = log;
}
#Override
public void run() {
for (int i = 0; i < 5000; i++) {
try {
log.log("This is entry " + i + " from thread " + Thread.currentThread().getId());
} catch (InterruptedException ex) {
}
}
System.out.println(Thread.currentThread().getId() + " is done");
}
}
//________________________________________________________________________________________________
/*
* This is the code for the actual logger
*
*/
private final BlockingQueue<String> queue = new ArrayBlockingQueue<>(10000);
private String fileName;
private Thread thread;
private Writer writer;
public ThreadedLog(String fileName) throws UnsupportedEncodingException, FileNotFoundException {
this.fileName = fileName;
thread = new Thread(new LoggingThread());
writer = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(fileName, true), "utf-8"));
thread.start();
}
private class LoggingThread implements Runnable {
#Override
public void run() {
try {
for (;;) {
ThreadedLog.this.writer.write(queue.take() + "\r\n");
ThreadedLog.this.writer.flush();
}
} catch (InterruptedException | IOException e) {
e.printStackTrace();
try {
ThreadedLog.this.writer.close();
} catch (Exception ex) {
}
}
}
}
public void log(String string) throws InterruptedException {
queue.put(string);
}
}