The group of application programming tools that operate multitasking is provided by Java
with two concepts, Process
and Thread
. Where a Process
describes a complete code operating environment, and Thread
is a form of Process
with a simpler design and exists within Process
. Each JVM
application defaults to being initialized with a Process
, and each Process
is defaulting to being initialized with a Thread
.
Here we will not deal with the management problem at the level of Process
, but only learn about how to create Thread
.
Runnable
interface:
java.lang.Runnable
Before thinking about parallelizing tasks, we need a common interface to define tasks. Instead of object A
describing a task whose launch method is .start()
and object B
describing another task whose launch method is .execute()
, here we have Runnable
to create the interface Generic programming for object
describes single tasks with a single .run()
method to launch them.
1 2 3 4 5 6 7 8 9 10 11 12 | <span class="token keyword">import</span> <span class="token namespace">java <span class="token punctuation">.</span> io <span class="token punctuation">.</span></span> <span class="token operator">*</span> <span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">Main</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> main <span class="token punctuation">(</span> <span class="token class-name">String</span> <span class="token punctuation">[</span> <span class="token punctuation">]</span> $args <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">Runnable</span> $task <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token class-name">System</span> <span class="token punctuation">.</span> out <span class="token punctuation">.</span> println <span class="token punctuation">(</span> <span class="token string">"Do something"</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> $task <span class="token punctuation">.</span> run <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">// -- end class</span> |
Now object
describing tasks such as $task
are created that have a common programming interface, but have not yet been executed on separate processes. The next step is that we need to create the code execution processes independent from the main operation of the main
method.
Thread
class:
java.util.Thread
We can use class Thread
to create object
that describe independent code execution processes in two ways: Because class Thread
has an implementation of Runnable
, we can create object
of the anonymous class
. and override
.run()
method; Or, we can also pass a object Runnable
to the Thread
‘s initializer.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | <span class="token keyword">import</span> <span class="token namespace">java <span class="token punctuation">.</span> io <span class="token punctuation">.</span></span> <span class="token operator">*</span> <span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">Main</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> main <span class="token punctuation">(</span> <span class="token class-name">String</span> <span class="token punctuation">[</span> <span class="token punctuation">]</span> $args <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">Runnable</span> $task <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token punctuation">{</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token class-name">Thread</span> <span class="token punctuation">.</span> sleep <span class="token punctuation">(</span> <span class="token number">1000</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token class-name">System</span> <span class="token punctuation">.</span> out <span class="token punctuation">.</span> println <span class="token punctuation">(</span> <span class="token string">"Extra thread"</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span> <span class="token class-name">Exception</span> $exception <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">System</span> <span class="token punctuation">.</span> out <span class="token punctuation">.</span> println <span class="token punctuation">(</span> $exception <span class="token punctuation">.</span> toString <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// -- Runnable</span> <span class="token class-name">Thread</span> $thread <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span> <span class="token punctuation">(</span> $task <span class="token punctuation">,</span> <span class="token string">"Thread name"</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> $thread <span class="token punctuation">.</span> start <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token class-name">System</span> <span class="token punctuation">.</span> out <span class="token punctuation">.</span> println <span class="token punctuation">(</span> <span class="token string">"Main thread"</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">// -- end class</span> |
Here we have the Thread.sleep(1000);
will pause the process of Thread
executing $task
. However, since we have placed $task
in a new process, main
‘s process is not affected; And as a result, the print statement "Main thread"
will be executed before the print statement in $task
.
1 2 3 4 5 6 | Main thread delay 1 second... Extra thread |
In case we want to merge the execution of a Thread
with any other process, we need to keep the reference address of that Thread
and call .join()
method in the process we want to merge. Here we will try to merge back to main
process by calling .join()
method right after .start()
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <span class="token keyword">import</span> <span class="token namespace">java <span class="token punctuation">.</span> io <span class="token punctuation">.</span></span> <span class="token operator">*</span> <span class="token punctuation">;</span> <span class="token keyword">class</span> <span class="token class-name">Main</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> main <span class="token punctuation">(</span> <span class="token class-name">String</span> <span class="token punctuation">[</span> <span class="token punctuation">]</span> $args <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">Runnable</span> $task <span class="token operator">=</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">.</span> <span class="token punctuation">;</span> <span class="token class-name">Thread</span> $thread <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Thread</span> <span class="token punctuation">(</span> $task <span class="token punctuation">,</span> <span class="token string">"Thread name"</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> $thread <span class="token punctuation">.</span> start <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> $thread <span class="token punctuation">.</span> join <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span> <span class="token class-name">Exception</span> $exception <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name">System</span> <span class="token punctuation">.</span> out <span class="token punctuation">.</span> println <span class="token punctuation">(</span> $exception <span class="token punctuation">.</span> toString <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token class-name">System</span> <span class="token punctuation">.</span> out <span class="token punctuation">.</span> println <span class="token punctuation">(</span> <span class="token string">"Main thread"</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">// -- end class</span> |
Operation result:
1 2 3 4 5 | delay 1 second... Extra thread Main thread |
Synchronized
In the previous article, when giving an overview of Java Collections Framework
, we saw that Java
provides additional versions thread-safe
data structures. The phrase thread-safe
means that these constructs are designed to ensure that: in case they are accessed and edited by many different thread
at the same time, the performance will always be the same as when working. with a single thread
.
To better understand this point, we will start with a self-defined data structure and assume that this structure will store all the data that describes the operating context of an application.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Context</span> <span class="token punctuation">{</span> <span class="token keyword">private</span> <span class="token keyword">int</span> data <span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token class-name">Context</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> data <span class="token operator">=</span> <span class="token number">0</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> increase <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> data <span class="token operator">+=</span> <span class="token number">1</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">void</span> decrease <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> data <span class="token operator">-=</span> <span class="token number">1</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">int</span> getData <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> data <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">// -- end Context</span> |
Now we have a object Context
shared by all components in the application. Let’s say we have thread A
doing increment and retrieval, and thread B
at the same time doing decrement and access. At this point, the operation result might look like this:
thread A
retrieves the value ofdata=0
and increments the value to1
.thread B
retrieves the value ofdata=0
and decrements the value to-1
.thread A
writes the value back to memorydata=1
.thread B
writes the value back to memorydata=-1
.thread A
retrieves the value and printsdata=-1
.thread B
retrieves the value and printsdata=-1
.
Thus, the result we expected for thread A
‘s operation logic is wrong. Instead of printing a value of 1
, thread A
‘s print statement prints -1
. And the Context
data structure that we define now is called non-threadsafe
– which means it is not safe to use in a multitasking environment. And to simplify the solution here, Java
provides a synchronized
keyword that can be used for methods and blocks of code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | <span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">SynchronizedContext</span> <span class="token punctuation">{</span> <span class="token keyword">private</span> <span class="token keyword">int</span> data <span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token class-name">Context</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> data <span class="token operator">=</span> <span class="token number">0</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">synchronized</span> <span class="token keyword">void</span> increase <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> data <span class="token operator">+=</span> <span class="token number">1</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">synchronized</span> <span class="token keyword">void</span> decrease <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> data <span class="token operator">-=</span> <span class="token number">1</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">synchronized</span> <span class="token keyword">int</span> getData <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token keyword">this</span> <span class="token punctuation">.</span> data <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">// -- end Context</span> |
And this is exactly how Java
creates thread-safe
versions of data structures. When there are multiple thread
concurrently calling a synchronized
method, suppose the first .increase()
called by thread A
will be processed first as above. Then all other method calls of SynchronizedContext
will pause to wait for .increase()
to finish executing on thread A
.
After .increase()
has finished executing, JVM
will continue to check thread thread A
‘s thread-id
among the remaining method calls and find .getData()
to print and will continue to prioritize thread A
handle this interaction. And the output we have here will be:
thread A
retrieves the value ofdata=0
and increments the value to1
.thread A
writes the value back to memorydata=1
.thread A
retrieves the value and printsdata=1
.thread B
retrieves the value ofdata=1
and decrements the value to0
.thread B
writes the value back to memorydata=0
.thread B
retrieves the value and printsdata=0
.
In case we need to convert a
non-threadsafe
data structure to asynchronized
type, we can use thesynchronized
methods ofjava.util.Collections
This may have been the right stop for the topic of Concurrency Programming
in the introductory Sub-Series of the language. Next, we were able to think about implementing mini project
to practice applying OOP
thinking to the code architecture of the software we want to build.
At this point, I had to change my mind many times between choosing to build a 2 player mode chess board and a data management application. However, whichever option you choose, you will need to create a graphical interface to interact with the user instead of the command-line window interface. The obvious remaining options are:
- Draw the interface in a web browser window with
HTML
,CSS
, andJavaScript
. - Or, draw the application interface independent of a certain
framework
that supportsJava
.
The first choice will entail learning about module java.net
to create a web server as back-end
that handles the core operating logic of the application using Java
. It sounds like it will be less effort because we already know about the front-end
language set of web programming. However, if you want to create an application that works offline
, Java
provides module.desktop
to support drawing user interfaces. If you don’t really like using the above web-based languages, you can accompany me in the next articles, learn about the java.awt
and javax.swing
graphical interface drawing package
.