I have created two threads and modified the run function so that one thread reads one line and the other writes the same line to the new file. This happens till the whole file is copied. The problem i am getting is that even though i have used variables to control that the threads execute one by one but still the threads are executing unevenly i.e one thread executes multiple times and then the control transfers. Any solutions i have attached the code. I am new to java as it is only for class assignment so the code might not be the most optimized.
public class thread1 extends Thread {
//To create producer and consumer as threads
//Shared variable
public static int x = 0;//checks if all lines are read
public static String line; /holds lines from file
public static int j = 0;//variable to switch between threads based upon its value
public thread1(String threadName) { //Constuctor
super(threadName); //Call to constructor of Thread class
}
public void run() {
while (x != -1)
{
if (Thread.currentThread().getName().contains("Reader")) {
if (x != -1&&j==0)
{
j=1;
String fileName = "d:/salfar.txt";
try {
// FileReader reads text files in the default encoding.
FileReader fileReader =
new FileReader(fileName);
// Always wrap FileReader in BufferedReader.
BufferedReader bufferedReader =
new BufferedReader(fileReader);
for (int check = 0; check <= x; check++) {
line = bufferedReader.readLine();
}
if (line == null) {
x = -1;
} else {
System.out.println(line);
x++;
}
// Always close files.
bufferedReader.close();
} catch (FileNotFoundException ex) {
System.out.println(
"Unable to open file '"
+ fileName + "'");
} catch (IOException ex) {
System.out.println(
"Error reading file '"
+ fileName + "'");
// Or we could just do this:
// ex.printStackTrace();
}
}
yield();
}
else if (Thread.currentThread().getName().contains("writer")) {
if (x != -1 && line != null&&j==1)
{
j=0;
String fileName = "d:/salfar1.txt";
try {
// Assume default encoding.
FileWriter fileWriter =
new FileWriter(fileName, true);
// Always wrap FileWriter in BufferedWriter.
BufferedWriter bufferedWriter =
new BufferedWriter(fileWriter);
// Note that write() does not automatically
// append a newline character.
bufferedWriter.write(line);
bufferedWriter.newLine();
System.out.println("y");
// Always close files.
bufferedWriter.close();
} catch (IOException ex) {
System.out.println(
"Error writing to file '"
+ fileName + "'");
// Or we could just do this:
// ex.printStackTrace();
}
}
Thread.yield();
}
else{}
}
}
public static void main(String[] args) {
thread1 p = new thread1("Reader");
thread1 c = new thread1("writer");
p.start();
c.start();
}
}
Thanks
You cannot control the order of thread execution. However, to perform read and write operation via separate threads, you should use BlockingQueue which has the following properties:
A Queue that additionally supports operations that wait for the queue to become non-empty when retrieving an element, and wait for space to become available in the queue when storing an element.
ReaderThread will read from the input file.
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.concurrent.BlockingQueue;
public class ReaderThread implements Runnable{
protected BlockingQueue<String> blockingQueue = null;
public ReaderThread(BlockingQueue<String> blockingQueue){
this.blockingQueue = blockingQueue;
}
#Override
public void run() {
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(new File("./inputFile.txt")));
String buffer =null;
while((buffer=br.readLine())!=null){
blockingQueue.put(buffer);
}
blockingQueue.put("EOF"); //When end of file has been reached
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch(InterruptedException e){
}finally{
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
WriterThread will write to output file.
import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.concurrent.BlockingQueue;
public class WriterThread implements Runnable{
protected BlockingQueue<String> blockingQueue = null;
public WriterThread(BlockingQueue<String> blockingQueue){
this.blockingQueue = blockingQueue;
}
#Override
public void run() {
PrintWriter writer = null;
try {
writer = new PrintWriter(new File("outputFile.txt"));
while(true){
String buffer = blockingQueue.take();
//Check whether end of file has been reached
if(buffer.equals("EOF")){
break;
}
writer.println(buffer);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch(InterruptedException e){
}finally{
writer.close();
}
}
}
From Launcher class start your multithreaded read and write.
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class Launcher {
public static void main(String[] args) {
BlockingQueue<String> queue = new ArrayBlockingQueue<String>(1024);
ReaderThread reader = new ReaderThread(queue);
WriterThread writer = new WriterThread(queue);
new Thread(reader).start();
new Thread(writer).start();
}
}
Here is my solutions. My idea is to use the actually file name that our threads will be reading and writing to. There is only one issue that we need to make sure of, that no two threads are trying to operate on the same file. The solution to this is to simply have a synchronized code block in your run method.
We must recall that Strings are not mutable in Java. Consider the following:
String s1 = "test.txt";
String s2 = "test.txt";
Now, we must ask our selves how does the jvm reuse the immutable "test.txt". In this case both s1 & s2 String objects point to the same "test.txt".
Understanding this concept will also do the trick for us:
public class Client {
public static void main( String args [] ) {
String filename = "test.txt";
String filename2 = "test.txt";
Reader reader = new Reader( filename ) ;
Writer writer = new Writer( filename2 ) ;
while(true) {
reader.run();
writer.run();
}
}
}
public class Writer implements Runnable {
public String filename;
public Writer( String filename ) {
this.filename = filename;
}
#Override
public void run() {
synchronized( this.filename ) {
System.out.println( "writing to a file:" + this.filename );
}
}
}
public class Reader implements Runnable {
public String filename;
public Reader( String filename ) {
this.filename = filename;
}
#Override
public void run() {
synchronized( this.filename ) {
System.out.println( "reading a file:" + this.filename );
}
}
}
Related
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'm writing a program that writes to a single file from both different threads on the same JVM and from different JVM's/processes. Is there a way to lock a file for both threads and processes, so that no matter how many threads/processes are trying to write at the same time, only 1 can write at a time?
Currently I have something similar to the following which works for locking threads, but not for blocking processes. If I try using FileLock on top of the implementation below it appears the synchronized stops working.
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import scripts.com.adz.commons.utils.FileUtilities;
import java.io.*;
public class Foo {
public static void main(String[] args) throws IOException {
Bar bar = new Bar();
bar.start();
while (true) {
FileUtilities.writeObjectToFile("C:\\test.html", "foo");
}
}
}
class Bar extends Thread {
#Override
public void run() {
while (true) {
try {
FileUtilities.writeObjectToFile("C:\\test.html", "bar");
} catch (IOException ignored) {}
}
}
}
class FileUtilitiess {
private static final Object _lock = new Object();
public static <T> T readObjectFromFile(File file) throws IOException, ClassNotFoundException {
synchronized (_lock) {
final byte[] bytes = FileUtils.readFileToByteArray(file);
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(bis = new ByteArrayInputStream(bytes));
return (T) ois.readObject();
} finally {
IOUtils.closeQuietly(ois);
IOUtils.closeQuietly(bis);
}
}
}
public static void writeObjectToFile(File file, Object object) throws IOException {
System.out.println("Sent object: " + object.toString());
synchronized (_lock) {
System.out.println("Writing object: " + object.toString());
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(bos = new ByteArrayOutputStream());
oos.writeObject(object);
FileUtils.writeByteArrayToFile(file, bos.toByteArray());
// - Start: For testing lock.
try {
Thread.sleep(10000);
} catch (InterruptedException ignored) {}
// - End: For testing lock.
} finally {
IOUtils.closeQuietly(oos);
IOUtils.closeQuietly(bos);
}
}
}
}
See FileLock javadoc:
File locks are held on behalf of the entire Java virtual machine.
That means that on the OS level different threads of your application will have the same right to access the locked region.
To lock the file access from different threads you have to encapsulate your file IO code and to enforce synchronized execution.
I am just trying to control processbuilder inputstream and outputstream from different class
It is main class
public class Controller
{
public static void main(String[]args)
{
Runner r=new Runner("Test");
r.activateInput();
r.setInput("Test");
}
}
It is other class to run process
import java.io.*;
public class Runner
{
boolean activeInput=true;
boolean active=true;
String input;
public Runner(String command)
{
try {
// create a new process
System.out.println("Creating Process...");
ProcessBuilder compile = new ProcessBuilder("java","TestOut");
compile.directory(new File("C:/Users/abhishek221192/Documents/Socket"));
Process process = compile.start();
OutputStream stdin = process.getOutputStream ();
InputStream stderr = process.getErrorStream ();
InputStream stdout = process.getInputStream ();
final BufferedReader reader = new BufferedReader (new InputStreamReader(stdout));
BufferedReader error = new BufferedReader (new InputStreamReader(stderr));
final BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(stdin));
//final Scanner scan=new Scanner(System.in);
Thread T=new Thread(new Runnable() {
#Override
public void run() {
while(active)
{
if(activeInput)
System.out.println(activeInput+" "+input);
String data ="Abhi";
data += "\n";
try {
if(activeInput){
writer.write(data);
writer.flush();
activeInput=false;
}
//
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
} );
T.start();
T.setName("Input");
Thread T1=new Thread(new Runnable() {
#Override
public void run() {
String line;
try{
while ((line = reader.readLine ()) != null) {
System.out.println(line);
}} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} );
T1.start();
T1.setName("Output");
/*
String line;
while ((line = error.readLine ()) != null) {
System.out.println(line);
}
*/
//stdout.close();
//error.close();
//T.stop();
//stdin.close();
//System.err.println("stdin closed");
active=false;
// close the output stream
System.out.println("Closing the output stream...");
//testProcessBuilder();
} catch (Exception ex) {
System.out.println("Error"+ex.getMessage());
}
}
public void activateInput()
{
this.activeInput=true;
System.out.println("active"+activeInput);
}
public void setInput(String input)
{
this.input=input;
}
}
It is TestOut code it include only one input statement
TestOut.java
import java.util.*;
public class TestOut
{
public static void main(String[]args)
{
Scanner sc=new Scanner(System.in);
System.out.println("Output hello TestOut");
System.out.println("Output1 "+sc.nextLine());
}
}
I am geting this output
Creating Process...
true null
Closing the output stream...
activetrue
Output hello TestOut
Output1 Abhi
r.setInput(); is not setting value
Couple of changes i made to make it work. the main problem with this piece of code is concurrency issues as two threads are working on same set of data. activeInput is being modified by Controller and by thread T
Change 1:
public synchronized void activateInput(boolean activate) {
this.activeInput = activate;
System.out.println("active" + activeInput);
}
if (activeInput) {
writer.write(data);
writer.flush();
activateInput(false);
}
declared method activateInput synchronized and replaced activateInput = false with the method call in thread T
Change 2:
// active = false;
commented out this line at the end of Runner() method because it is stopping the writer Thread unnecessarily.
Change 3:
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Added this at the end of Writer Thread's while loop to give writer Thread T some breathing space and to give it a chance on reading the values.
Output:
Here is the output i got:
Creating Process...
activetrue
Output hello TestOut
true Test
activefalse
Output1 Abhi
Hope this helps.
/*main method*/
Server server = new Server(tcpPort);
new Thread(server).start();
try {
Thread.sleep(1000*60); /* 60 seconds*/
} catch (InterruptedException e) {
e.printStackTrace();
}
server.stop;
...
This is the code I've written. A Server thread is started, and runs for 60 seconds. How do I change this to run infinitely, ending when a user enters Enter via a BufferedReader or something.
I've tried it with
while(!input.equals("")) { /* just pseudocoded here...*/
Thread.sleep(10);
}
but this will my Server stop from working correctly. My clients won't even connect to it anymore. Have I made a design mistake or is this an easy problem to solve?
Try this basic Chatting Server that I wrote. This server simply keeps running in loop and broadcast the message send by the clients to all the other clients associated with this server.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
public class Server {
// ///----------------------------------------Instance Variable Fields
ServerSocket ss = null;
Socket incoming = null;
// ///----------------------------------------Instance Variable Fields
// ///---------------------------------------- static Variable Fields
public static ArrayList<Socket> socList = new ArrayList<Socket>();
// ///---------------------------------------- static Variable Fields
public void go() {
try {
ss = new ServerSocket(25005);
while (true) {
incoming = ss.accept();
socList.add(incoming);
System.out.println("Incoming: " + incoming);
new Thread(new ClientHandleKaro(incoming)).start();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
ss.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class ClientHandleKaro implements Runnable {
InputStream is = null;
OutputStream os = null;
InputStreamReader isr = null;
BufferedReader br = null;
PrintWriter pw = null;
boolean isDone = false;
Socket sInThread = null;
public ClientHandleKaro(Socket sxxx) {
this.sInThread = sxxx;
}
#Override
public void run() {
if (sInThread.isConnected()) {
System.out.println("Welcamu Clienta");
System.out.println(socList);
}
try {
is = sInThread.getInputStream();
System.out.println("IS: " + is);
isr = new InputStreamReader(is);
br = new BufferedReader(isr);
os = sInThread.getOutputStream();
pw = new PrintWriter(os, true);
String s = new String();
while ((!isDone) && (s = br.readLine()) != null) {
String[] asx = s.split("-");
System.out.println("On Console: " + s);
// pw.println(s);
Thread tx = new Thread(new ReplyKaroToClient(s,
this.sInThread));
tx.start();
if (asx[1].trim().equalsIgnoreCase("BYE")) {
System.out.println("I am inside Bye");
isDone = true;
}
}
} catch (IOException e) {
System.out.println("Thanks for Chatting.....");
} finally {
try {
Thread tiku = new Thread(new ByeByeKarDo(sInThread));
tiku.start();
try {
tiku.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Accha to hum Chalte hain !!!");
System.out.println(socList);
br.close();
pw.close();
sInThread.close();
} catch (IOException e) {
}
}
}
}
class ReplyKaroToClient implements Runnable {
public String mString;
public Socket mSocket;
public ReplyKaroToClient(String s, Socket sIn) {
this.mString = s;
this.mSocket = sIn;
}
#Override
public void run() {
for (Socket sRaW : socList) {
if (mSocket.equals(sRaW)) {
System.out.println("Mai same hun");
continue;
} else {
try {
new PrintWriter(sRaW.getOutputStream(), true)
.println(mString);
} catch (IOException e) {
System.out.println("Its in Catch");
}
}
}
}
}
class ByeByeKarDo implements Runnable {
Socket inCom;
public ByeByeKarDo(Socket si) {
this.inCom = si;
}
#Override
public void run() {
try {
new PrintWriter(inCom.getOutputStream(), true)
.println("You have Logged Out of Server... Thanks for ur Visit");
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new Server().go();
}
}
Start with this SO thread: How to create a basic Java Server? . It will give you an example how to write a very simple server.
Key thing to note there is the serverSocket.accept() . It will block - in other words it will WAIT forever for a client to connect, or it will fail in the case of some error. Once a client is connected, you will get a clientSocket that you can use to read what client wrote, and also write to it.
It is really a good starting point for understanding Java network programming. However, I recommend you read more about this topic. Something like this: http://beej.us/guide/bgnet/
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);
}
}