You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Similar goals: Split up workload into multiple parts and partition tasks into different, multiple tasks for these multiple actors. Two common ways of doing this are multi-threaded programs and multi-process systems.
Differences
Criteria
Thread
Process
Def
A thread exists within a process and has less resource consumption
A running instance of a program
Resources
Multiple threads within the same process will share the same heap space but each thread still has its own registers and its own stack.
Each process has independent system resources. Inter process mechanism such as pipes, sockets, sockets need to be used to share resources.
Overhead for creation/termination/task switching
Faster due to very little memory copying (just thread stack). Faster because CPU caches and program context can be maintained
Slower because whole process area needs to be copied. Slower because all process area needs to be reloaded
Synchronization overhead
Shared data that is modified requires special handling in the form of locks, mutexes and primitives
No synchronization needed
Use cases
Threads are a useful choice when you have a workload that consists of lightweight tasks (in terms of processing effort or memory size) that come in, for example with a web server servicing page requests. There, each request is small in scope and in memory usage. Threads are also useful in situations where multi-part information is being processed – for example, separating a multi-page TIFF image into separate TIFF files for separate pages. In that situation, being able to load the TIFF into memory once and have multiple threads access the same memory buffer leads to performance benefits.
Processes are a useful choice for parallel programming with workloads where tasks take significant computing power, memory or both. For example, rendering or printing complicated file formats (such as PDF) can sometimes take significant amounts of time – many milliseconds per page – and involve significant memory and I/O requirements. In this situation, using a single-threaded process and using one process per file to process allows for better throughput due to increased independence and isolation between the tasks vs. using one process with multiple threads.
Create threads
Implementing the Runnable interface
The runnable interface has the following very simple structure
publicinterfaceRunnable
{
voidrun();
}
Steps
Create a class which implements the Runnable interface. An object of this class is a Runnable object
Create an object of type Thread by passing a Runnable object as argument to the Thread constructor. The Thread object now has a Runnable object that implements the run() method.
The start() method is invoked on the Thread object created in the previous step.
We can create a thread by extending the Thread class. This will almost always mean that we override the run() method, and the subclass may also call the thread constructor explicitly in its constructor.
Extending the Thread Class vs Implementing the Runnable Interface
Implementing runnable is the preferrable way.
Java does not support multiple inheritance. Therefore, after extending the Thread class, you can't extend any other class which you required. A class implementing the Runnable interface will be able to extend another class.
A class might only be interested in being runnable, and therefore, inheriting the full overhead of the Thread class would be excessive.
Thread and Runnable are complement to each other for multithreading not competitor or replacement. Because we need both of them for multi-threading.
For Multi-threading we need two things:
Something that can run inside a Thread (Runnable).
Something That can start a new Thread (Thread).
So technically and theoretically both of them is necessary to start a thread, one will run and one will make it run (Like Wheel and Engine of motor vehicle).
Deadlock
Def
A deadlock is a situation where a thread is waiting for an object lock that another thread holds, and this second thread is waiting for an object lock that the first thread holds. Since each thread is waiting for the other thread to relinquish a lock, they both remain waiting forever.
Conditions
Mutal Exclusion: Only one process can access a resource at a given time. (Or more accurately, there is limited access to a resource. A deadlock could also occur if a resource has limited quantity. )
Hold and Wait: Processes already holding a resource can request additional resources, without relinquishing their current resources.
No Preemption: One process cannot forcibly remove another process' resource.
Circular Wait: Two or more processes form a circular chain where each process is waiting on another resource in the chain.
packagedesignThreadSafeEntity.delayedTaskScheduler;
importjava.util.PriorityQueue;
importjava.util.concurrent.atomic.AtomicInteger;
publicclassScheduler
{
// order task by time to runprivatePriorityQueue<Task> tasks;
// privatefinalThreadtaskRunnerThread;
// State indicating the scheduler is running// Why volatile? As long as main thread stops, runner needs to has visibility.privatevolatilebooleanrunning;
// Task id to assign to submitted tasks// AtomicInteger: Threadsafe. Do not need to add locks when assigning task Ids// Final: Reference of atomicInteger could not be changedprivatefinalAtomicIntegertaskId;
publicScheduler()
{
tasks = newPriorityQueue<>();
taskRunnerThread = newThread( newTaskRunner() );
running = true;
taskId = newAtomicInteger( 0 );
// start task runner threadtaskRunnerThread.start();
}
publicvoidschedule( Tasktask, longdelayMs )
{
// Set time to run and assign task idlongtimeToRun = System.currentTimeMillis() + delayMs;
task.setTimeToRun( timeToRun );
task.setId( taskId.incrementAndGet() );
// Put the task in queuesynchronized ( this )
{
tasks.offer( task );
this.notify(); // only a single background thread waiting
}
}
publicvoidstop( ) throwsInterruptedException
{
// Notify the task runner as it may be in wait()synchronized ( this )
{
running = false;
this.notify();
}
// Wait for the task runner to terminatetaskRunnerThread.join();
}
privateclassTaskRunnerimplementsRunnable
{
@Overridepublicvoidrun()
{
while ( running )
{
// Need to synchronize with main threadsynchronized( Scheduler.this )
{
try
{
// task runner is blocked when no tasks in queuewhile ( running && tasks.isEmpty() )
{
Scheduler.this.wait();
}
// check the first task in queuelongnow = System.currentTimeMillis();
Taskt = tasks.peek();
// delay exhausted, execute taskif ( t.getTimeToRun() < now )
{
tasks.poll();
t.run();
}
else
{
// no task executable, waitScheduler.this.wait( t.getTimeToRun() - now );
}
}
catch ( InterruptedExceptione )
{
Thread.currentThread().interrupt();
}
}
}
}
}
publicstaticvoidmain( String[] args ) throwsInterruptedException
{
Schedulerscheduler = newScheduler();
scheduler.schedule( newTask(), 1000000 );
scheduler.schedule( newTask(), 1000 );
Thread.sleep( 7000 );
scheduler.stop();
}
}
classTaskimplementsComparable<Task>
{
// When the task will be runprivatelongtimeToRun;
privateintid;
publicvoidsetId( intid )
{
this.id = id;
}
publicvoidsetTimeToRun( longtimeToRun )
{
this.timeToRun = timeToRun;
}
publicvoidrun()
{
System.out.println( "Running task " + id );
}
publicintcompareTo( Taskother )
{
return (int) ( timeToRun - other.getTimeToRun() );
}
publiclonggetTimeToRun()
{
returntimeToRun;
}
}