A thread is a single sequential flow of control within a process
The multithreading is simultaneous execution (or pseudocontemporary) of different threads within the same process
-
Lightweight Process: Threads are lighter than processes, sharing resources within a process.
-
Resource Sharing: Threads share resources like memory and open files within a process.
-
Multithreading: Programs can execute multiple threads simultaneously, leveraging multicore architectures.
-
Independent Scheduling: Threads can be scheduled and executed independently by the operating system.
-
Thread States: Threads can be in various states during their lifecycle, such as ready, running, waiting, and terminated.
-
Inter-Thread Communication: Threads communicate through shared variables, semaphores, mutex, and other synchronization mechanisms.
-
Synchronization: Synchronization is essential to prevent issues like race conditions and ensure safe access to shared resources.
-
Main Thread: Multithreaded applications have at least one main thread, serving as the program's starting point.
-
Thread Priority: Threads can have different priorities affecting their execution sequence.
-
Thread State Implementation: Threads can be implemented at the user level (without involving the kernel) or the kernel level.
-
Deadlock and Starvation: Incorrect thread handling can lead to deadlock and starvation issues.
-
Thread Pooling: Thread pooling is used to manage and reuse threads, improving performance and reducing the overhead of creating new threads.
- Many to one: Threads are implemented at the application level, their scheduler runs in user space, and is not part of the OS.
- Cost-effective scheduling
- Loss of parallelism
- One to one: Threads are handled directly by the O.S. as primitive entities (native threads)
- Very efficient scheduling
- High creation and synchronization times
- Many to many: l S.O. has a pool of native threads (workers), e.g. each of which is assigned from time to time a Application threads (user threads) to be executed
- Efficient and inexpensive to create and manage a thread
- Very flexible
- Difficult to define the size of the workers and how the two will cooperate Scheduler
Objective: Collect a multiplicity of threadswithin a single group to facilitate management operations (e.g. suspend/ Stop/restart the execution of a set of threads with a single invocation).
In Java, the JVM associates eachthread to a group when the thread. This association is permanent and cannot be modified.
ThreadGroup myThreadGroup = new ThreadGroup("My group");
Thread myThread = new Thread(myThreadGroup, "MyThread");
Default choice: The JVM creates a Thread group called "main", which will be the default group.
In general, daemons are processes thatPerform an endless loop of waiting for requests and execution of the same.
Java recognizes the importance of daemon threads and It introduces two types of threads:
- User thread
- Daemon thread
The only difference: When JVM termined the last user thread, also ends the deamon thread execution.
- Native threads: the JVM uses support for the multithreading provided by the O.S.
- Green-thread: the JVM shall take full responsibility for themanagement of threads, ignored by the O.S. that sees the JVM as a single-threaded process.
Java provides two ways to implement thread:
- as a subclass of the
Thread
class - as a class that implements the interface
Runnable
- Thread class:
- More immediate and simple mode
- Lack of flexibility resulting from the need to inherit from the Thread class, which prevents you from inheriting from other classes
- Runnable interface:
- Greater flexibility resulting from being able to be a subclass of any other class, useful to overcome the impossibility of having multiple inheritance in Java
- Less simple and more cumbersome mode
start()
- Starts the execution of a thread. The JVM invokes the
run()
method of the newly created thread
- Starts the execution of a thread. The JVM invokes the
sleep(long time)
- Blocks a thread from executing for the
time
specified in time.
- Blocks a thread from executing for the
join()
- Blocks the calling thread while waiting for the thread on which you invoke the method to terminate.
To solve this problem we can use synchronization with keywork synchronized
We can use it on different scope:
- Single Method
- Single Class Method
- Instruction Block
public void NameMethod(){
synchronized(this){
//operation with synchronization
}
}
public synchronized void NameMethod(){
//operation
}
There are several methods for synchronizing:
wait()
- Blocks the invoking thread from executing while waiting for another thread to invoke the
notify()
ornotifyAll()
methods for that object.
- Blocks the invoking thread from executing while waiting for another thread to invoke the
notify()
- Wakes up a single thread among those that are waiting. If more than one thread is waiting, the choice is arbitrary.
notifyAll()
- Exactly like
notify()
, but it wakes up all threads waiting for the object in question.
- Exactly like
public synchronized int get(){
while(avaible == false){
try{
wait();
}catch (InterruptedException e){}
}
avaible = false;
notifyAll();
//Operion of get method
}
public synchronized void push(int value){
while(avaible == true){
try{
wait();
} catch(InterruptedException e){}
}
avaible = true;
notifyAll();
}