[Threading to manage simulated printing jobs]

  • Thread starter getsanjay.sharma
  • Start date
G

getsanjay.sharma

Hello to all Javascript programmers out there. :)

I am really ashamed to say that even after 6 months of intermittent
Java programming I have been a complete failure at grasping the
concepts or the real thing behind 'threading'. My mind just seems to
go in a state of deadlock and I keep hours looking at the screen
trying to come up with a design to get the problem solved using
threads. I am OK with normal Java programs. Also here in my case I
have not used the convenience classes provided by java so that I can
get my concepts right.

Here I have written a program which simulates a printing job in which
'Consumer' is a printing device or software and 'Producer' submits a
printing job. But the output I get is highly deterministic i.e. the
same everytime I don't even know if I have got it right or wrong. Some
comments / pointers / alternate designs / tips / revelations would be
greatly appreciated.

import java.sql.Timestamp;
import java.util.*;

public class ThreadTime {
@SuppressWarnings("unused")
public static void main(String[] args) throws Exception {
PrintQueue queue = new PrintQueue();
Producer producer = null;
for (int i = 0; i < 100; ++i) {
producer = new Producer(queue, "c:/" + i + ".txt");
}
new Consumer(queue);
new Consumer(queue);
new Consumer(queue);
}
}

class Consumer {
private static int gId;

private PrintQueue queue;

private String id;

private Consumer() {
}

private Runnable job = new Runnable() {
public void run() {
// start consuming the print jobs and print them
try {
for (;;) {
//System.out.println("Inside run of producer");
Thread.sleep(10);
PrintJob job = queue.getJob();
if (job != null)
System.out.println(id + job.print());
}
} catch (Exception e) {
e.printStackTrace();
}
}
};

public Consumer(PrintQueue queue) throws Exception {
this.queue = queue;
this.id = "Consumer" + gId;
gId++;
Thread t = new Thread(job);
t.join(); /* Does this even do anything? */
t.start();
}
}

class Producer {
private PrintQueue queue;

private String file;

public Producer(PrintQueue queue, String file) throws Exception {
this.queue = queue;
this.file = file;
Thread t = new Thread(job);
t.join(); /* Does this even do anything? */
t.start();
}

private Runnable job = new Runnable() {
public void run() {
try {
//System.out.println("Inside run of producer");
Thread.sleep(500);
queue.putJob(new PrintJob(file, new Timestamp(new Date()
.getTime())));
} catch (Exception e) {
e.printStackTrace();
}
}
};
}

class PrintQueue {
public List<PrintJob> queue;

public static int jobId;

public PrintQueue() {
queue = new LinkedList<PrintJob>();
}

public synchronized PrintJob getJob() {
if (queue.size() != 0)
return (queue.remove(0));
else
return (null);
}

public synchronized void putJob(PrintJob job) {
queue.add(job);
}
}

class PrintJob {
private static int jobId;

public int id;

public Timestamp time;

public String path;

public PrintJob(String path, Timestamp time) {
this.id = jobId;
this.path = path;
this.time = time;
jobId++;
}

private PrintJob() {
}

public String print() {
return (this.toString());
}

public String toString() {
return (" Id: " + id + " Path: " + path + " Time: " + time);
}
}

Thanks a lot for your valuable time.

Regards,
S T S
 
J

Joshua Cranmer

Here I have written a program which simulates a printing job in which
'Consumer' is a printing device or software and 'Producer' submits a
printing job. But the output I get is highly deterministic i.e. the
same everytime I don't even know if I have got it right or wrong. Some
comments / pointers / alternate designs / tips / revelations would be
greatly appreciated.

What is the output?
class Consumer {
private Runnable job = new Runnable() {
public void run() {
// start consuming the print jobs and print them
try {
for (;;) {
//System.out.println("Inside run of producer");
Thread.sleep(10);
PrintJob job = queue.getJob();
if (job != null)
System.out.println(id + job.print());
}
} catch (Exception e) {
e.printStackTrace();
}
}
> };

Two things:
1. Don't use tabs in Usenet posts.
2. There should typically be some way to tell the Consumer to stop running.

public Consumer(PrintQueue queue) throws Exception {
> [ ... ]
t.join(); /* Does this even do anything? */
Joining a thread waits for it stop. Since the thread hasn't started yet,
it doesn't do anything.
}
}

[ ... ]

Try posting some of the output so we could help better.
 
L

Lew

Hello to all Javascript programmers out there. :)

Wrong group. They won't be listening here.
I am really ashamed to say that even after 6 months of intermittent
Java programming I have been a complete failure at grasping the
concepts or the real thing behind 'threading'.

Join the crowd. Nearly all Java programmers have yet to grok threading.
class Consumer {
private static int gId;

Accessed by many threads, yet you don't synchronize those accesses. Not safe.

Do not use TAB characters in Usenet posts.
private PrintQueue queue;

private String id;

private Consumer() {
}

You do not need this constructor. Also, it's conventional to place all
constructor definitions together.
private Runnable job = new Runnable() {
public void run() {
// start consuming the print jobs and print them
try {
for (;;) {
//System.out.println("Inside run of producer");

Use logging, not System.out.println(). And isn't this the consumer?
Thread.sleep(10);
PrintJob job = queue.getJob();

You'd better make sure the queue is synchronized!
if (job != null)
System.out.println(id + job.print());

Use logging, not System.out.println(). And you forgot your braces.
}
} catch (Exception e) {
e.printStackTrace();
}
}
};

public Consumer(PrintQueue queue) throws Exception {
this.queue = queue;
this.id = "Consumer" + gId;
gId++;
Synchronize!

Thread t = new Thread(job);
t.join(); /* Does this even do anything? */

Have you read the Javadocs on Thread.join?
<http://java.sun.com/javase/6/docs/api/java/lang/Thread.html#join()>
It causes the current thread to wait for the target thread to finish. Of
course, in your case it hasn't started yet.
t.start();

I am thinking it's a bad idea to fire off threads or do any significant work
in the constructor.

Buy and study /Java Concurrency in Practice/ by Brian Goetz, et al.
 
D

Daniel Pitts

Hello to all Javascript programmers out there. :)

I am really ashamed to say that even after 6 months of intermittent
Java programming I have been a complete failure at grasping the
concepts or the real thing behind 'threading'. My mind just seems to
go in a state of deadlock and I keep hours looking at the screen
trying to come up with a design to get the problem solved using
threads.
Many people have a hard time grasping threads, especially if they try
to understand it without being taught exactly how they work. I
suggest reading about it, see below.
I am OK with normal Java programs. Also here in my case I
have not used the convenience classes provided by java so that I can
get my concepts right.

Here I have written a program which simulates a printing job in which
'Consumer' is a printing device or software and 'Producer' submits a
printing job. But the output I get is highly deterministic i.e. the
same everytime I don't even know if I have got it right or wrong. Some
comments / pointers / alternate designs / tips / revelations would be
greatly appreciated.
[snip code]

The best pointer I can give you: Read the book "Java Concurrency In
Practice" <http://www.javaconcurrencyinpractice.com/>. It is a great
book that explains the ins and outs of multi-threaded programming in
Java. After you read it, not only will you be able to diagnose the
problems with your code, you'll be able to design it in a much more
robust manor.

What you need to learn about is synchronization and ordering. Unless
you synchronize your threads some way (either by using synchronize
*appropriately*), they may interact in unexpected ways. Don't just
add synchronization willy-nilly either, it is possible to figure out
where you need to sync to achieve thread safety. All that information
and more is in the book I recommended.

Good luck,
Daniel.
 
G

getsanjay.sharma

What is the output?
The output is continuous stream of:
Consumer0 Id: 0 Path: c:/0.txt Time: 2007-09-10 22:38:54.859
Consumer1 Id: 1 Path: c:/1.txt Time: 2007-09-10 22:38:54.859
Consumer2 Id: 2 Path: c:/2.txt Time: 2007-09-10 22:38:54.859
[...]

Accessed by many threads, yet you don't synchronize those accesses. Not safe.

Do not use TAB characters in Usenet posts.
Yes, I will keep that in mind from now on.
You do not need this constructor. Also, it's conventional to place all
constructor definitions together.


Use logging, not System.out.println(). And isn't this the consumer?
I was told by someone not to use Javas' inbuilt logging API and rather
use 'log4j' and since this wa s a test program, I thought SOP's would
suffice the purpose.
You'd better make sure the queue is synchronized!
But I thought that since the PrintQueue methods are synchronized, I
don't need to do anything else, no?
Have you read the Javadocs on Thread.join?
<http://java.sun.com/javase/6/docs/api/java/lang/Thread.html#join()>
It causes the current thread to wait for the target thread to finish. Of
course, in your case it hasn't started yet.


I am thinking it's a bad idea to fire off threads or do any significant work
in the constructor.
I picked up this idea from the 'Java programming language' book. :(
Buy and study /Java Concurrency in Practice/ by Brian Goetz, et al.
Yes, I'll try to get my hands on this book since everyone on this NG
seems to be recommending it but some quick fixes for this program
would be really appreciated.

Thanks and regards,
S T S
 
D

Daniel Pitts

What is the output?

The output is continuous stream of:
Consumer0 Id: 0 Path: c:/0.txt Time: 2007-09-10 22:38:54.859
Consumer1 Id: 1 Path: c:/1.txt Time: 2007-09-10 22:38:54.859
Consumer2 Id: 2 Path: c:/2.txt Time: 2007-09-10 22:38:54.859
[...]

Accessed by many threads, yet you don't synchronize those accesses. Not safe.
Do not use TAB characters in Usenet posts.

Yes, I will keep that in mind from now on.




You do not need this constructor. Also, it's conventional to place all
constructor definitions together.
Use logging, not System.out.println(). And isn't this the consumer?

I was told by someone not to use Javas' inbuilt logging API and rather
use 'log4j' and since this wa s a test program, I thought SOP's would
suffice the purpose.


You'd better make sure the queue is synchronized!

But I thought that since the PrintQueue methods are synchronized, I
don't need to do anything else, no?


Have you read the Javadocs on Thread.join?
<http://java.sun.com/javase/6/docs/api/java/lang/Thread.html#join()>
It causes the current thread to wait for the target thread to finish. Of
course, in your case it hasn't started yet.

I am thinking it's a bad idea to fire off threads or do any significant work
in the constructor.

I picked up this idea from the 'Java programming language' book. :(
Buy and study /Java Concurrency in Practice/ by Brian Goetz, et al.

Yes, I'll try to get my hands on this book since everyone on this NG
seems to be recommending it but some quick fixes for this program
would be really appreciated.

Thanks and regards,
S T S

The quick fix is to use Executor, and pass in a Callable object that
does what you want.
 
L

Lew

Careless. System.out.println() is not for logging. The nice thing about
logging libs is that their overhead all but vanishes in production, so you
don't have to deploy code that's different from what you had in development.

Don't use System.out.println() for logging.
Lew:
getsanjay.sharma:

All I said was to make sure the queue is synchronized. I didn't say it wasn't.

Individual method synchronization works as long as no single operation
requires more than one method call into the queue, as in your situation.

When you get this version working, think about using a blocking queue instead
of a non-blocking one. Your consumers will spin through CPU as you have
written things currently.

You might consider using one of the built-in Java queue classes, such as
java.util.concurrent.Class LinkedBlockingQueue<E>

Incidentally,
producer = new Producer(queue, "c:/" + i + ".txt");

displays the anti-pattern of hard-coded "magic" strings. Also, since you
apparently are running this on Windows, placing many files into the root
directory is kind of a Bad Idea.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,571
Members
45,045
Latest member
DRCM

Latest Threads

Top