Java - Concurrency - Multi-Thread 1 - Implements Runnable or Extends Thread

1. Difference between Process and Thread

  • Threads are used for small tasks, whereas processes are used for more ‘heavyweight’ tasks – basically the execution of applications.
  • Threads within the same process share the same address space, whereas different processes do not.
  • A process can have multiple threads, and at least one

2. Pros and Cons for Multi-Threads

  • Pro: resolves the problem to run multiple parts at the same time
  • Cons: too many multi-threads will decrease the efficiency

3. JVM multi-thread

There are at least two threads when JVM starts up

  • the main function thread
  • the garbage collection thread
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Subobj extends Object{
public void finalize(){
sop("subobj destroyed");
}
}

class Demo{
public static void main(String[] args){
new Subobj();
new Subobj();

System.gc(); //启动系统垃圾回收器

new Subobj();
sop("Hello World!");
}
}

4. Thread Class in Java

Java’s Thread class also implements Runnable interface.

5. How to create a Java Thread

1. Extends Thread class and Override run() method

  1. Define a class MyThread extends Thread class
  2. Override run() methods in MyThread class
  3. Create an object t of MyThread class
  4. Call start() method to start the thread, which results in executing run() method
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 1.
class MyThread extends Thread {
// 2.
@Override
public void run() {
// ...
}
}

public avoid anotherMethod {
// 3.
MyThread t = new MyThread();

// 4.
t.start();
}

2. Implements Runnable interface and Override run() method (Most Frequently Used)

  1. Define a class that implements Runnable interface
  2. Override run() methods in the impl class, which basically encapsulates the business logic to run() method
  3. Create a new Thread object, and pass in the impl class to that instance as constructor parameter

    Why? Because the business logic of a thread is all well encapsulated in the run() method, a Thread instance needs to be specified how it should run when initialized

  4. Call start() method of that Thread instance

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// 1.
class MyRunnable implements Runnable {
// 2.
@Override
public void run() {
// ...
}
}

public void anotherMethod {
// 3.
Thread t = new Thread(new MyRunnable());

// 4.
t.start();
}
```


## 6. Advantages to `implements Runnable` over `extends Thread`

1. Separate and encapsulate the business logic of a thread from subclasses of `Thread`, which conforms to the core idea of object oriented programming

2. Avoided the limitation of Java's single extension mechanism.

- When you `extends Thread` class, after that you can’t extend any other class which you required. (As you know, Java does not allow inheriting more than one class).
- When you `implements Runnable`, you can save a space for your class to extend any other class in future or now.

3. `implements Runnable` allows sharing the same instance

- When you extends Thread class, each of your thread creates unique object and associate with it.
- When you implements Runnable, it shares the same object to multiple threads.


The following example helps you to understand more clearly.

```java
class ImplementsRunnable implements Runnable {

private int counter = 0;

public void run() {
counter++;
System.out.println("ImplementsRunnable : Counter : " + counter);
}
}

class ExtendsThread extends Thread {

private int counter = 0;

public void run() {
counter++;
System.out.println("ExtendsThread : Counter : " + counter);
}
}

public class ThreadVsRunnable {

public static void main(String args[]) throws Exception {
//Multiple threads share the same object.
ImplementsRunnable rc = new ImplementsRunnable();
Thread t1 = new Thread(rc);
t1.start();
Thread.sleep(1000); // Waiting for 1 second before starting next thread
Thread t2 = new Thread(rc);
t2.start();
Thread.sleep(1000); // Waiting for 1 second before starting next thread
Thread t3 = new Thread(rc);
t3.start();

//Creating new instance for every thread access.
ExtendsThread tc1 = new ExtendsThread();
tc1.start();
Thread.sleep(1000); // Waiting for 1 second before starting next thread
ExtendsThread tc2 = new ExtendsThread();
tc2.start();
Thread.sleep(1000); // Waiting for 1 second before starting next thread
ExtendsThread tc3 = new ExtendsThread();
tc3.start();
}
}

Output of the above program.

1
2
3
4
5
6
ImplementsRunnable : Counter : 1
ImplementsRunnable : Counter : 2
ImplementsRunnable : Counter : 3
ExtendsThread : Counter : 1
ExtendsThread : Counter : 1
ExtendsThread : Counter : 1

In the Runnable interface approach, only one instance of a class is being created and it has been shared by different threads. So the value of counter is incremented for each and every thread access.

Whereas, Thread class approach, you must have to create separate instance for every thread access. Hence different memory is allocated for every class instances and each has separate counter, the value remains same, which means no increment will happen because none of the object reference is same.

So, use Runnable interface when you want to access the same resource from the group of threads. Avoid using Thread class here, because multiple objects creation consumes more memory and it becomes a big performance overhead.

Reference: https://manikandanmv.wordpress.com/tag/extends-thread-vs-implements-runnable/

Methods in Thread class

We can get the name of a Thread via getName().

Thread’s naming convention is like Thread-#(start from 0)

The main thread’s name is main.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class MyRunnable implements Runnable{
@Override
public void run(){
System.out.println(Thread.currentThread().getName());
}
}

class Demo{
public static void main(String[] args){
MyRunnable myRunnable = new MyRunnable();

Thread t1 = new Thread(myRunnable);
Thread t2 = new Thread(myRunnable);
Thread t3 = new Thread(myRunnable);
Thread t4 = new Thread(myRunnable);

t1.start();
t2.start();
t3.start();
t4.start();
}
}

Output:

1
2
3
4
Thread-0
Thread-2
Thread-1
Thread-3