My questions are:
Does a Java program, by default, cause creation of only 1 thread?
If yes, and if we create a multi threaded program, when do multiple threads access the same code of a Java object?
For example I have a Java program with 2 methods - add() and sub(). In what scenario will 2 or more threads run the 'add()' method?
Isn't code always thread safe, as multiple threads will access different sections of code?
If not, please show an example program where thread safety is a concern.
Don't think of "sections of code", think of where the data lives and how many threads are accessing that actual data.
Local variables live on the stack of the thread they are being used in and are thread safe since they are different data "containers" per thread.
Any data that lives on the heap, like instance or static fields, are not inherently thread-safe because if more than one thread accesses that data then they might have contention.
We could get more complicated and talk about where the data really is but this basic explanation should give you a good idea of what's going on.
The below code gives an example of an instance that is shared by two threads, in this case both threads are accessing the same array list, which is pointing to the same array data containers in the heap. Run it a couple times and you'll eventually see a failure. If you comment out one of the threads it will work correctly every time, counting down from 99.
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) {
MyRunnable r = new MyRunnable();
new Thread(r).start();
new Thread(r).start();
}
public static class MyRunnable implements Runnable {
// imagine this list living out in the heap and both threads messing with it
// this is really just a reference, but the actual data is in the heap
private List<Integer> list = new ArrayList<>();
{ for (int i = 0; i < 100; i++) list.add(i); }
#Override public void run() {
while (list.size() > 0) System.out.println(list.remove(list.size() - 1));
}
}
}
1) Does a Java program, by default, cause creation of only 1 thread?
Really depends on what your code is doing. A simple System.out.println() call might probably just create one thread. But as soon as you for example raise a Swing GUI window, at least one other thread will be around (the "event dispatcher thread" that reacts to user input and takes care of UI updates).
2) If yes, and if we create a multi threaded program, when do multiple threads access the same code of a Java object?
Misconception on your end. Objects do not have code. Basically, a thread will run a specific method; either its own run() method, or some other method made available to it. And then the thread just executes that method, and any other method call that is triggered from that initial method.
And of course, while running that code, that thread might create other objects, or manipulate the status of already existing objects. When each thread only touches a different set of objects, then no problems arise. But as soon as more than one thread deals with the same object state, proper precaution is required (to avoid indeterministic behavior).
Your question suggests that you might not fully understand what "thread" means.
When we learned to program, they taught us that a computer program is a sequence of instructions, and they taught us that the computer executes those instructions one-by-one, starting from some well-defined entry point (e.g., the main() routine).
OK, but when we talk about multi-threaded programs, it no longer is sufficient to say that "the computer" executes our code. Now we say that threads execute our code. Each thread has its own idea of where it is in your program, and if two or more threads happen to be executing in the same function at the same time, then each of them has its own private copy of the function's arguments and local variables.
So, You asked:
Does a Java program, by default, cause creation of only 1 thread?
A Java program always starts with one thread executing your code, and usually several other threads executing JVM code. You don't normally need to be aware of the JVM threads. The one thread that executes your code starts its work at the beginning of your main() routine.
Programmers often call that initial thread the "main thread." Probably they call it that because it calls main(), but be careful! The name can be misleading: The JVM doesn't treat the "main thread" any differently from any other thread in a multi-threaded Java program.
if we create a multi threaded program, when do multiple threads access the same code of a Java object?
Threads only do what your program tells them to do. If you write code for two different threads to call the same function, then that's what they will do. But, let's break that question down a bit...
...First of all, how do we create a multi-threaded program?
A program becomes multi-threaded when your code tells it to become multi-threaded. In one simple case, it looks like this:
class MyRunnable implements Runnable {
public void run() {
DoSomeUsefulThing();
DoSomeOtherThing();
}
}
MyRunnable r = new MyRunnable();
Thread t = new Thread(r);
t.start();
...
Java creates a new thread when some other thread in your program calls t.start(). (NOTE! The Thread instance, t, is not the thread. It is only a handle that your program can use to start the thread and inquire about its thread's state and control it.)
When the new thread starts executing program instructions, it will start by calling r.run(). As you can see, the body of r.run() will cause the new thread to DoSomeUsefulThing() and then DoSomeOtherThing() before r.run() returns.
When r.run() returns, the thread is finished (a.k.a., "terminated", a.k.a., "dead").
So,
when do multiple threads access the same code of a Java object?
When your code makes them do it. Let's add a line to the example above:
...
Thread t = new Thread(r);
t.start();
DoSomeUsefulThing();
...
Note that the main thread did not stop after starting the new thread. It goes on to execute whatever came after the t.start() call. In this case, the next thing it does is to call DoSomeUsefulThing(). But that's the same as what the program told the new thread to do! If DoSomeUsefulThing() takes any significant time to complete, then both threads will be doing it at the same time... because that's what the program told them to do.
please show an example program where thread safety is a concern
I just did.
Think about what DoSomeUsefulThing() might be doing. If it's doing something useful, then it almost certainly is doing something to some data somewhere. But, I didn't tell it what data to operate on, so chances are, both threads are doing something to the same data at the same time.
That has a lot of potential to not turn out well.
One way to fix that is to tell the function what data to work on.
class MyDataClass { ... }
Class MyRunnable implements Runnable {
private MyDataClass data;
public MyRunnable(MyDataClass data) {
this.data = data;
}
public void run() {
DoSomeUsefulThingWITH(data);
DoSomeOtherThingWITH(data);
}
}
MyDataClass dat_a = new MyDataClass(...);
MyDataClass dat_b = new MyDataClass(...);
MyRunnable r = new MyRunnable(dat_a);
Thread t = new Thread(r);
t.start();
DoSomeUsefulThingWITH(dat_b);
There! Now the two threads are doing the same thing, but they are doing it to different data.
But what if you want them to operate on the same data?
That's a topic for a different question. Google for "mutual exclusion" to get started.
Depends on the implementation. Only one thread (the "main thread") will invoke the public static void main(String[]) method, but that doesn't mean other threads weren't started for other tasks.
A thread will access the "same code" if you program it to do so. I'm not sure what your idea of "section of code" is or where the idea that two threads will never access the same "section" at the same time comes from, but it's quite trivial to create thread-unsafe code.
import java.util.ArrayList;
import java.util.List;
public class Main {
public static void main(String[] args) throws InterruptedException {
List<Object> list = new ArrayList<>();
Runnable action = () -> {
while (true) {
list.add(new Object());
}
};
Thread thread1 = new Thread(action, "tread-1");
thread1.setDaemon(true); // don't keep JVM alive
Thread thread2 = new Thread(action, "thread-2");
thread2.setDaemon(true); // don't keep JVM alive
thread1.start();
thread2.start();
Thread.sleep(1_000L);
}
}
An ArrayList is not thread-safe. The above code has two threads constantly trying to add a new Object to the same ArrayList for approximately one second. It's not guaranteed, but if you run that code you might see an ArrayIndexOutOfBoundsException or something similar. Regardless of any exceptions being thrown, the state of the ArrayList is in danger of being corrupted. This is because state is updated by multiple threads with no synchronization.
Related
This question already has an answer here:
NetworkOnmainThreadException android+Rxjava
(1 answer)
Closed 10 months ago.
Does this line:
ClientThread.ClientSocket.getInputStream().read()
takes ClientThread's method and executes it on MainUI thread, or does it tell ClientThread to execute it?
It results in MainThreadNetworking Exception so I believe it's the first option, sadly. If so, how can I execute that method in the ClientThread instead?
There is no way to tell another thread to execute something. So, no, the above simply runs it in your thread. Note, there's the concept 'Thread -a thing that runs on an OS core' and 'java.lang.Thread - an object that represents that concept'. They are not quite identical. I'll use j.l.Thread to indicate the Thread object and just thread for the OS concept. j.l.Thread is just an object, it's not particularly magical. Just interacting with a j.l.Thread instance is just.. interacting with an object. It doesn't convey magical 'anything you do with this object somehow runs in a separate thread' powers.
There are only only 2 ways to tell another thread (OS-level or j.l.Thread) to execute something, i.e., only 2 ways to use j.l.Thread to actually run stuff in separate threads:
When creating a j.l.Thread, you pass along the 'run()' code (either passing a Runnable, or extending Thread and supplying a run() method). When some thread runs the code thatThreadObject.start() (note: not run!) - then that starts an actual thread, and that newly created thread will, after initializing, begin by executing the code in that run() method of the j.l.Thread object.
By programming it. In other words, perhaps some thread looks like this:
private class Runner extends Thread {
private final ArrayBlockingQueue <Runnable> queue = new ArrayBlockingQueue<>(1000);
public void offer(Runnable r) {
queue.add(r);
}
#Override public void run() {
while (true) {
Runnable r = queue.take();
r.run();
}
}
}
Then, imagine some code is running in a thread (not the thread represented by the j.l.Thread instance made from the above code), and calls thatThreadObj.offer(() -> System.out.println("Hello!");...
then eventually the thread represented by that j.l.Thread will run it. Because you programmed it to do this.
If you want something like that, note that the java.util.concurrent package has implementations of this concept (ExecutorPool and friends). Don't write it yourself.
I'm trying to learn threads in Java. I've followed two different tutorials, but I feel like I'm not really getting the concept. As I understand it, when you create threads, you use the Thread class, and then embedding your own object within the thread. I can do that, but I can't figure out how to access the instance variables within the "embedded" object.
Suppose as a learning exercise, I wanted to create three threads which would go off and do work individually of one another. I could define this object to "drive" the threads:
public class StoogeObject implements Runnable {
String name;
int data;
public StoogeObject(String name, int data){
this.name=name;
this.data=data;
}
#Override
public void run() {
System.out.println("Thread "+this.name+" has this data: "+this.data);
// Do useful work here
System.out.println("Thread "+this.name+" is exiting...");
}
public String getName(){
return this.name;
}
}
Then, in a driver program, I would launch my threads:
public class driver {
public static void main(String[] args){
Thread stooge1 = new Thread(new StoogeObject("Larry", 123));
Thread stooge2 = new Thread(new StoogeObject("Curly", 456));
Thread stooge3 = new Thread(new StoogeObject("Moe", 789));
stooge1.start();
stooge2.start();
stooge3.start();
if(stooge1.isAlive())
System.out.println("From main(): "+stooge1.getName());
}
}
Output is:
From main(): Thread-0
Thread Larry has this data: 123
Thread Curly has this data: 456
Thread Moe has this data: 789
Thread Larry is exiting...
Thread Curly is exiting...
Thread Moe is exiting...
I was surprised when the stooge1.getName() line in main() produced "Thread-0", not "Larry". I was expecting the getName() method I wrote in stoogeObject.java to override and return the instance variable String name in this instance. Instead, I'm getting the name of the Thread, not the StoogeObject.
So... The stooge1 thread has a StoogeObject within it, but I don't know how to access its instance variables. More significantly, this example makes me wonder if I'm missing the point of threads. If I want my Larry, Curly, & Moe objects to go off and do productive work AND keep their own instance variables, is using threads the wrong way to go here? Should I start over, making these objects into processes?
I can't figure out how to access the instance variables within the "embedded" object.
You access them in exactly the same way that you would access the instance variables of any other object.
The "embedded" object, FYI, is called the thread's target or the thread's delegate.
There is nothing special about the target of a Thread. It's just an object.
I was surprised when the stooge1.getName() line in main() produced "Thread-0", not "Larry". I was expecting ... Instead, I'm getting the name of the Thread, not the StoogeObject.
That's because the Thread object and the StoogeObject are different objects.
this example makes me wonder if I'm missing the point of threads.
There are two different ways that threads can be used in a program. The first (which is what people think of more often than not) is that threads are how a Java program can make use of more than one CPU if your platform has more than one CPU. (Virtually all modern servers and workstations have more than one these days, and it's getting to where a lot of cell phones and tablets have more than one as well.) If your platform has, say eight CPUs, then up to eight of your threads may be able to run simultaneously if that many of them are "ready to run."
The second way to use threads in a program is to wait for things. For example, if your program is a server that has to waits for input from each of N clients, and respond to it; you can structure it as N threads that each just listen to and respond to one client. That often makes the code easier to understand. (Just like, it's easier to juggle one ball than it is to juggle N balls).
is using threads the wrong way to go here? Should I start over, making these objects into processes?
Threads can be much more tightly coupled than processes because the threads of a single program all share the same virtual address space (i.e., in a Java program, they all share the same heap). Communication between threads usually is one or two orders of magnitude faster than communication between different processes on the same machine.
If you need fine-grained communication between them, then they definitely should be threads. A good rule of thumb is that, an application should never spawn a new process unless there is a really good reason why it should not be just another thread.
If you want to access the runnable object that you pass to the thread, you need to keep a reference to it.
Here is an example:
stoogeObject obj = new stoogeObject("Larry", 123);
Thread stooge1 = new Thread(obj);
stooge1.start();
System.out.println(obj.getName());
This will print Larry.
Keep in mind that if the name variable from the stoogeObject instance is changed during the thread's runtime, you'll have to wait for that thread to finish (or finish changing the variable) in order to get the correct value.
You can do that by using join().
stoogeObject obj = new stoogeObject("Larry", 123);
Thread stooge1 = new Thread(obj);
stooge1.start();
stooge1.join();
System.out.println(obj.getName());
Here the System.out.println(obj.getName()) statement is executed only after the thread is done.
I was surprised when the stooge1.getName() line in main() produced "Thread-0", not "Larry". I was expecting the getName() method I wrote in stoogeObject.java to override and return the instance variable String name in this instance. Instead, I'm getting the name of the Thread, not the StoogeObject.
How is this surprising? You never set the thread's name, then you call stooge1.getName(), and stooge1 is the Thread, and you're getting precisely what you asked for: "the name of the Thread".
The only thing the Thread knows about the Runnable that you pass it is that it has a run() method, it doesn't know or care about any other things you've added to your Runnable implementation.
If you want to set the thread's name, either use the Thread constructor that takes a name:
Thread stooge1 = new Thread(new StoogeObject(...), "Thread's Name");
Or set its name later:
stooge1.setName("Thread's Name");
So... The stooge1 thread has a StoogeObject within it, but I don't know how to access its instance variables.
It's up to you to store and manage your StoogeObjects, and Titus' answer covers this nicely. I just wanted to add a bit on top of that to answer your thread name related question.
As a side note: Once you wrap your head around the fundamentals, check out the official high-level concurrency tutorial, particularly the section on "executors". The Java API provides a few really convenient high-level constructs for concurrency that you might find useful in certain situations.
I know that it is not possible to restart a used Java Thread object, but I don't find an explanation why this is not allowed; even if it is guaranteed that the thread has finished (see example code below).
I don't see why start() (or at least a restart()) method should not be able to somehow reset the internal states - whatever they are - of a Thread object to the same values they have when the Thread object is freshly created.
Example code:
class ThreadExample {
public static void main(String[] args){
Thread myThread = new Thread(){
public void run() {
for(int i=0; i<3; i++) {
try{ sleep(100); }catch(InterruptedException ie){}
System.out.print(i+", ");
}
System.out.println("done.");
}
};
myThread.start();
try{ Thread.sleep(500); }catch(InterruptedException ie){}
System.out.println("Now myThread.run() should be done.");
myThread.start(); // <-- causes java.lang.IllegalThreadStateException
} // main
} // class
I know that it is not possible to
restart a used Java Thread object, but
I don't find an explanation why this
is not allowed; even if it is
guaranteed that the thread has
finished (see example code below).
My guestimation is that Threads might be directly tied (for efficiency or other constrains) to actual native resources that might be re-startable in some operating systems, but not in others. If the designers of the Java language had allowed Threads to be re-started, they might limit the number of operating systems on which the JVM can run.
Come to think of it, I cannot think of a OS that allows a thread or process to be restarted once it is finished or terminated. When a process completes, it dies. You want another one, you restart it. You never resurrect it.
Beyond the issues of efficiency and limitations imposed by the underlying OS, there is the issue of analysis and reasoning. You can reason about concurrency when things are either immutable or have a discrete, finite life-time. Just like state machines, they have to have a terminal state. Is it started, waiting, finished? Things like that cannot be easily reasoned about if you allow Threads to resurrect.
You also have to consider the implications of resurrecting a thread. Recreate its stack, its state, is is safe to resurrect? Can you resurrect a thread that ended abnormally? Etc.
Too hairy, too complex. All that for insignificant gains. Better to keep Threads as non-resurrectable resources.
I'd pose the question the other way round - why should a Thread object be restartable?
It's arguably much easier to reason about (and probably implement) a Thread that simply executes its given task exactly once and is then permanently finished. To restart threads would require a more complex view on what state a program was in at a given time.
So unless you can come up with a specific reason why restarting a given Thread is a better option than just creating a new one with the same Runnable, I'd posit that the design decision is for the better.
(This is broadly similar to an argument about mutable vs final variables - I find the final "variables" much easier to reason about and would much rather create multiple new constant variables rather than reuse existing ones.)
Because they didn't design it that way. From a clarity standpoint, that makes sense to me. A Thread represents a thread of execution, not a task. When that thread of execution has completed, it has done its work and it just muddies things were it to start at the top again.
A Runnable on the other hand represents a task, and can be submitted to many Threads as many times as you like.
Why don't you want to create a new Thread? If you're concerned about the overhead of creating your MyThread object, make it a Runnable and run it with a new Thread(myThread).start();
Java Threads follow a lifecycle based on the State Diagram below. Once the thread is in a final state, it is over. That is simply the design.
You can kind of get around this, either by using a java.util.concurrent.ThreadPoolExecutor, or manually by having a thread that calls Runnable.run() on each Runnable that it is given, not actually exiting when it is finished.
It's not exactly what you were asking about, but if you are worried about thread construction time then it can help solve that problem. Here's some example code for the manual method:
public class ReusableThread extends Thread {
private Queue<Runnable> runnables = new LinkedList<Runnable>();
private boolean running;
public void run() {
running = true;
while (running) {
Runnable r;
try {
synchronized (runnables) {
while (runnables.isEmpty()) runnables.wait();
r = runnables.poll();
}
}
catch (InterruptedException ie) {
// Ignore it
}
if (r != null) {
r.run();
}
}
}
public void stopProcessing() {
running = false;
synchronized (runnables) {
runnables.notify();
}
}
public void addTask(Runnable r) {
synchronized (runnables) {
runnables.add(r);
runnables.notify();
}
}
}
Obviously, this is just an example. It would need to have better error-handling code, and perhaps more tuning available.
If you are concerned with the overhead of creating a new Thread object then you can use executors.
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class Testes {
public static void main(String[] args) {
Executor executor = Executors.newSingleThreadExecutor();
executor.execute(new Testes.A());
executor.execute(new Testes.A());
executor.execute(new Testes.A());
}
public static class A implements Runnable{
public void run(){
System.out.println(Thread.currentThread().getId());
}
}
}
Running this you will see that the same thread is used for all Runnable objects.
A Thread is not a thread. A thread is an execution of your code. A Thread is an object that your program uses to create and, manage the life-cycle of, a thread.
Suppose you like playing tennis. Suppose you and your friend play a really awesome set. How would your friend react if you said, "That was incredible, let's play it again." Your friend might think you were nuts. It doesn't make sense even to talk about playing the same set again. If you play again you're playing a different set.
A thread is an execution of your code. It doesn't make sense to even talk about "re-using" a thread of execution for same reason that it makes no sense to talk about re-playing the same set in tennis. Even if another execution of your code executes all the same statements in the same order, it's still a different execution.
Andrzej Doyle's asked, "Why would you want to re-use a Thread?" Why indeed? If a Thread object represents a thread of execution---an ephemeral thing that you can't even talk about re-using---then why would you want or expect the Thread object to be re-useable?
i've been searching the same solution which you seem to be looking for, and i resolved it in this way. if you occur mousePressed Event you can terminate it also reuse it, but it need to be initialized, as you can see below.
class MouseHandler extends MouseAdapter{
public void mousePressed(MouseEvent e) {
if(th.isAlive()){
th.interrupt();
th = new Thread();
}
else{
th.start();
}
}
}
I have a class which basically does the same series of steps twice. Sounds like a perfect example of where to multithread your program. My question is though if I can do this with only two threads. Here is the general jist of things
Tester implements Runnable{
Thread obj1Thread, obj2Thread;
MyObj obj1, obj2;
String obj1Results, obj2Results;
void runTests(){
obj1Thread = new Thread(this, "ob1 thread");
obj2Thread = new Thread(this, "ob2 thread");
obj1.start();//builds up obj1
obj2.start();//builds up obj2
if(obj1 and obj2 are finished building){
System.out.println(obj1);
System.out.println(obj2);
}
obj1Thread.startSecondPhase()//runs a separate function that tests obj1 vs ob2. Essentially test(ob1, ob2)
obj2Thread.startSecondPhase()//runs a separate function that tests obj2 vs ob1. Essentially test(ob2, ob1)
if(obj1 and obj2 are finished testing){
System.out.println(obj1Results);
System.out.println(obj2Results);
}
}
}
I have gotten the first part - building up the objects - working. My questions are now -
How can I get the main thread to wait for the two threads to finish their first part? Perhaps the main would do a wait on both objects and then after the threads notifyAll they do a wait on the main thread? But then how do the threads get a hold of the main thread? Perhaps with this?
How can I have this 'second phase' of the run function without making a new class with a new thread and a new specific run function? I dont want to have to make a new class and everything for every little task.
To clarify the sequence of events I want specifically is -
Main thread initializes and starts two threads
Both threads simultaneously build their respective objects
When both threads finish building they pause. Then main thread prints the objects out in order.
After main thread is done, the two threads continue their code to a testing phase simultaneously
When the threads are done the main thread prints the results out. Could probably use a join() here
Edit: Also, how can I tell the specific threads which objects I want them to work on? Right now Im doing it in a kinda hacky way (i'm working off the thread name).
I would use higher-level abstractions: use an execute and ExecutorService.invokeAll(Collection<? extends Callable<T>> tasks), which returns a list of Future.
Your main thread can
dispatch two tasks,
obtain two futures,
print the results, then
dispatch two more tasks
The executor service and futures will handle all the concurrency under the hood.
EDIT:
I see your comment:
A special Runnable class just to implement basically one line of code?
Perhaps I'm being too idealistic but that feels wrong to me.
You typically use ananymous inner classes in such case:
Future future = executorService.submit(new Runnable() {
public void run() {
System.out.println("Asynchronous task");
}
});
Nothing wrong with that. When Java has lambda it will become even shorter.
Future future = executorService.submit(() -> {System.out.println("Asynchronous task");});
I understand the concept behind threading and have written threads in other languages, but I am having trouble understanding how to adapt them to my needs in java.
Basicly at present I have a vector of objects, which are read in from a file sequentially.
The file then has a list of events, which need to happen concurrently so waiting for one event to finish which takes 20-30 seconds is not an option.
There is only a couple of methods in the object which deal with these events. However from looking at tutorials, objects must extend/implement threads/runnable however if the object is in a thread making a method call to that object seems to happen sequentially anyway.
An y extra information would be appreciated as I am clearly missing something I am just not quite sure what!
So to summarise how can I execute a single method using a thread?
To start a thread you call start() on an instance of Thread or a subclass thereof. The start() method returns immediately. At the same time, the other thread (the one incarnated by the Thread instance) takes off, and proceeds with executing the run() method of the Thread instance.
Managing threads is not as easy as it seems. For a smoother API, try using an Executor (see the classes in java.util.concurrent).
The best thing to do in Java is create another class that takes in the data you need to process and performs whatever you need it to perform:
class Worker implements Runnable{
Object mydata;
Worker(Object data)
{
mydata = data;
}
#override
void run()
{
//process the data
System.out.println(data.toString());
//or if you want to use your class then:
YourClass yc = (YourClass)myData;
yc.methodB();
}
}
class YourClass
{
private final ExecutorService executor = Executors.newCachedThreadPool();
private ArrayList<Object> list;
YourClass()
{
list = new ArrayList<Object>();
list.add(new Object());
...
...
list.add(new Object());
}
void methodA()
{
for(Object item : list )
{
// Create a new thread with the worker class taking the data
executor.execute(new Worker(item));
}
}
void methodB(){/*do something else here*/}
}
Note that instead of getting the data, you can pass the actual class that you need the method to be invoked on:
executor.execute(new Worker(new MyClass()));
In the run method of the Worker class you invoke whatever you need to invoke on MyClass... the executor creates a new thread and calls run on your Worker. Each Worker will run in a separate thread and it will be parallel.
Thomas has already given the technical details. I am going to try and focus on the logic.
Here is what I can suggest from my understanding of your problem.
Lets say you have a collection of objects of type X (or maybe even a mix of different types). You need to call methods foo and/or bar in these objects based on some event specified. So now, you maybe have a second collection that stores those.
So we have two List objects (one for the X objects and other for the events).
Now, we have a function execute that will take X, and the event, and call foo or bar. This execute method can be wrapped in a thread, and executed simultaneously. Each of these threads can take one object from the list, increment the counter, and execute foo/bar. Once done, check the counter, and take the next one from the list. You can have 5 or more of these threads working on the list.
So, as we see, the objects coming from file do not have to be the Thread objects.
You have to be very careful that the List and counter are synchronized. Much better data structures are possible. I am sticking to a crude one for ease of understanding.
Hope this helps.
The key to threads is to remember that each task that must be running must be in its own thread. Tasks executing in the same thread will execute sequentially. Dividing the concurrent tasks among separate threads will allow you to do your required cocurrent processing.