Tread là gì? Multi- thread là gì? Cách tạo Thread trong java.

Đăng bởi: Admin | Lượt xem: 4460 | Chuyên mục: Java

Trong bài viết này, chúng ta sẽ đi tìm hiểu các khái niệm cơ bản: Thread là gì? Multi- thread là gì? và tạo Thread trong java bằng cách extend từ Thread Class hoặc implement interface Runnable


Thread là gì? Multi-thread là gì?

Thread (luồng) về cơ bản là một tiến trình con (sub-process). Một đơn vị xử lý nhỏ nhất của máy tính có thể thực hiện một công việc riêng biệt. Trong Java, các luồng được quản lý bởi máy ảo Java (JVM).

Multi-thread (đa luồng) là một tiến trình thực hiện nhiều luồng đồng thời. Một ứng dụng Java ngoài luồng chính có thể có các luồng khác thực thi đồng thời làm ứng dụng chạy nhanh và hiệu quả hơn.

VD: Trình duyệt web hay các chương trình chơi nhạc là 1 ví dụ điển hình về đa luồng.

+ Khi duyệt 1 trang web, có rất nhiều hình ảnh, CSS, javascript… được tải đồng thời bởi các luồng khác nhau.

+ Khi play nhạc, chúng ta vẫn có thể tương tác được với nút điều khiển như: Play, pause, next, back … vì luồng phát nhạc là luồng riêng biệt với luồng tiếp nhận tương tác của người dùng.

Đa nhiệm (multitasking)

Multitasking: Là khả năng chạy đồng thời một hoặc nhiều chương trình cùng một lúc trên một hệ điều hành. Hệ điều hành quản lý việc này và sắp xếp lịch phù hợp cho các chương trình đó. Ví dụ, trên hệ điều hành Windows chúng ta có làm việc đồng thời với các chương trình khác nhau như: Microsoft Word, Excel, Media Player, …

Chúng ta sử dụng đa nhiệm để tận dụng tính năng của CPU.

Đa nhiệm có thể đạt được bằng hai cách:

  1. Đa nhiệm dựa trên đơn tiến trình (Process) – Đa tiến trình (Multiprocessing).
    • Mỗi tiến trình có địa chỉ riêng trong bộ nhớ, tức là mỗi tiến trình phân bổ vùng nhớ riêng biệt.
    • Tiến trình là nặng.
    • Sự giao tiếp giữa các tiến trình có chi phí cao.
    • Chuyển đổi từ tiến trình này sang tiến trình khác đòi hỏi thời gian để đăng ký việc lưu và tải các bản đồ bộ nhớ, các danh sách cập nhật, …
  2. Đa nhiệm dựa trên luồng (Thread) – Đa luồng (MultiThreading).
    • Các luồng chia sẻ không gian địa chỉ ô nhớ giống nhau.
    • Luồng là nhẹ.
    • Sự giao tiếp giữa các luồng có chi phí thấp.

Đa tiến trình (multiprocessing) và đa luồng (multithreading) cả hai được sử dụng để tạo ra hệ thống đa nhiệm (multitasking). Nhưng chúng ta sử dụng đa luồng nhiều hơn đa tiến trình bởi vì các luồng chia sẻ một vùng bộ nhớ chung. Chúng không phân bổ vùng bộ nhớ riêng biệt để tiết kiệm bộ nhớ, và chuyển đổi ngữ cảnh giữa các luồng mất ít thời gian hơn tiến trình.

Ưu điểm của đa luồng

  • Nó không chặn người sử dụng vì các luồng là độc lập và bạn có thể thực hiện nhiều công việc cùng một lúc.
  • Mỗi luồng có thể dùng chung và chia sẻ nguồn tài nguyên trong quá trình chạy, nhưng có thể thực hiện một cách độc lập.
  • Luồng là độc lập vì vậy nó không ảnh hưởng đến luồng khác nếu ngoại lệ xảy ra trong một luồng duy nhất.
  • Có thể thực hiện nhiều hoạt động với nhau để tiết kiệm thời gian. Ví dụ một ứng dụng có thể được tách thành : luồng chính chạy giao diện người dùng và các luồng phụ nhiệm gửi kết quả xử lý đến luồng chính.

Nhược điểm của đa luồng

  • Càng nhiều luồng thì xử lý càng phức tạp.
  • Xử lý vấn đề về tranh chấp bộ nhớ, đồng bộ dữ liệu khá phức tạp.
  • Cần phát hiện tránh các luồng chết (dead lock), luồng chạy mà không làm gì trong ứng dụng cả.

Deadlock (Khoá chết) là gì? Deadlock xảy ra khi 2 tiến trình đợi nhau hoàn thành, trước khi chạy. Kết quả của quá trình là cả 2 tiến trình không bao giờ kết thúc.

Cách tạo Thread trong Java

Trong java ta có thể tạo ra một luồng bằng một trong hai cách sau: tạo 1 đối tượng của lớp được extend từ class Thread hoặc implements từ interface Runnable.

Tạo luồng bằng cách extend từ lớp Thread

Để tạo luồng bằng cách tạo lớp kế thừa từ lớp Thread, ta phải làm các công việc sau:

  1. Khai báo 1 lớp mới kế thừa từ lớp Thread
  2. Override lại phương thức run ở lớp này, những gì trong phương thức run sẽ được thực thi khi luồng bắt đầu chạy. Sau khi luồng chạy xong tất cả các câu lệnh trong phương thức run thì luồng cũng tự hủy.
  3. Tạo 1 thể hiện (hay 1 đối tượng) của lớp ta vừa khai báo.
  4. Sau đó gọi phương thức start() của đối tượng này để bắt đầu thực thi luồng.

public class TheadSimple extends Thread {
    public void run() {
         System.out.println("thread is running...");
    }     
    public static void main(String args[]) {
         TheadSimple t1 = new TheadSimple();        
         t1.start();
   }
}

Lưu ý :

  • Tuy ta khai báo những công việc cần làm của luồng trong phương thức run() nhưng khi thực thi luồng ta phải gọi phương thức start(). Vì đây là phương thức đặc biệt mà java xây dựng sẵn trong lớp Thread, phương thức này sẽ cấp phát tài nguyên cho luồng mới rồi chạy phương thức run() ở luồng này. Vì vậy, nếu ta gọi phương thức run() mà không gọi start() thì cũng tương đương với việc gọi 1 phương thức của 1 đối tượng bình thường và phương thức vẫn chạy trên luồng mà gọi phương thức chứ không chạy ở luồng mới tạo ra, nên vẫn chỉ có 1 luồng chính làm việc chứ ứng dụng vẫn không phải là đa luồng.
  • Sau khi start một thread, nó không bao giờ có thể được start lại. Nếu bạn làm như vậy, một ngoại lệ IllegalThreadStateException sẽ xảy ra.

Tạo luồng bằng cách implement từ Interface Runnable

Để tạo luồng bằng cách hiện thực từ Interface Runnable, ta phải làm các công việc sau :

  1. Khai báo 1 lớp mới implements từ Interface Runnable
  2. Hiện thực phương thức run() ở lớp này, những gì trong phương thức run() sẽ được thực thi khi luồng bắt đầu chạy. Sau khi luồng chạy xong tất cả các câu lệnh trong phương thức run thì luồng cũng tự hủy.
  3. Tạo 1 thể hiện (hay 1 đối tượng) của lớp ta vừa khai báo. (VD : Tên đối tượng là r1)
  4. Tạo 1 thể hiện của lớp Thread bằng phương thức khởi tạo : Thread(Runnable target)
    • Runnable target: Là 1 đối tượng thuốc lớp được implements từ giao diện Runnable.
    • Ví dụ: Thread t1 = new Thread(r1);
  5. Gọi phương thức start() của đối tượng t1.
public class RunnableSimple implements Runnable {
    public void run() {
        System.out.println("thread is running...");
    }
     public static void main(String args[]) {
        RunnableSimple runable = new RunnableSimple();
        Thread t1 = new Thread(runable);
        t1.start();
    }
}

Khi nào implements từ interface Runnable?

+ Cách hay được sử dụng và được yêu thích là dùng interface Runnable, bởi vì nó không yêu cầu phải tạo một lớp kế thừa từ lớp Thread. Trong trường hợp ứng dụng thiết kế yêu cầu sử dụng đa kế thừa, chỉ có interface mới có thể giúp giải quyết vấn đề. Ngoài ra, Thread Pool rất hiểu quả và có thể được cài đặt, sử dụng rất hơn giản.
+ Trong trường hợp còn lại ta có thể kế thừa từ lớp Thread.

Ví dụ minh họa sử dụng đa luồng

Ví dụ Tạo luồng bằng cách extend từ class Thread

Tạo luồng extend từ class Thead

public class ThreadDemo extends Thread {
    private Thread t;
    private String threadName;
     ThreadDemo(String name) {
        threadName = name;
        System.out.println("Creating " + threadName);
    }
     @Override
    public void run() {
        System.out.println("Running " + threadName);
        try {
            for (int i = 4; i > 0; i--) {
                System.out.println("Thread: " + threadName + ", " + i);
                // Let the thread sleep for a while.
                Thread.sleep(50);
            }
        } catch (InterruptedException e) {
            System.out.println("Thread " + threadName + " interrupted.");
        }
        System.out.println("Thread " + threadName + " exiting.");
    }
     public void start() {
        System.out.println("Starting " + threadName);
        if (t == null) {
            t = new Thread(this, threadName);
            t.start();
        }
    }
 }


Chương trình sử dụng đa luồng:


public class ThreadDemoTest {

    public static void main(String args[]) {

        System.out.println("Main thread running... ");

        ThreadDemo T1 = new ThreadDemo("Thread-1-HR-Database");

        T1.start();

        ThreadDemo T2 = new ThreadDemo("Thread-2-Send-Email");

        T2.start();

        System.out.println("==> Main thread stopped!!! ");

    }

}

Kết quả thực hiện chương trình trên:


Main thread running...

Creating Thread-1-HR-Database

Starting Thread-1-HR-Database

Creating Thread-2-Send-Email

Starting Thread-2-Send-Email

==> Main thread stopped!!!

Running Thread-1-HR-Database

Running Thread-2-Send-Email

Thread: Thread-2-Send-Email, 4

Thread: Thread-1-HR-Database, 4

Thread: Thread-1-HR-Database, 3

Thread: Thread-2-Send-Email, 3

Thread: Thread-2-Send-Email, 2

Thread: Thread-1-HR-Database, 2

Thread: Thread-2-Send-Email, 1

Thread: Thread-1-HR-Database, 1

Thread Thread-2-Send-Email exiting.

Thread Thread-1-HR-Database exiting.

Kết quả chương trình trên được giải thích thông qua hình bên dưới:

Ví dụ Tạo luồng bằng cách implement từ Interface Runnable

Tạo luồng implement từ Interface Runnable

class RunnableDemo implements Runnable {
    private Thread t;
    private String threadName;
     RunnableDemo(String name) {
        threadName = name;
        System.out.println("Creating " + threadName);
    }
     @Override
    public void run() {
        System.out.println("Running " + threadName);
        try {
            for (int i = 4; i > 0; i--) {
                System.out.println("Thread: " + threadName + ", " + i);
                // Let the thread sleep for a while.
                Thread.sleep(50);
            }
        } catch (InterruptedException e) {
            System.out.println("Thread " + threadName + " interrupted.");
        }
        System.out.println("Thread " + threadName + " exiting.");
    }
     public void start() {
        System.out.println("Starting " + threadName);
        if (t == null) {
            t = new Thread(this, threadName);
            t.start();
        }
    }
 }

Chương trình sử dụng đa luồng:

public class RunnableDemoTest {
    public static void main(String args[]) {
        System.out.println("Main thread running... ");
        RunnableDemo R1 = new RunnableDemo("Thread-1-HR-Database");
        R1.start();
        RunnableDemo R2 = new RunnableDemo("Thread-2-Send-Email");
        R2.start();
        System.out.println("==> Main thread stopped!!! ");
    }
}

Kết quả thực thi chương trình trên:
 

Main thread running... 
Creating Thread-1-HR-DatabaseStarting 
Thread-1-HR-DatabaseCreating 
Thread-2-Send-EmailStarting 
Thread-2-Send-Email
==> Main thread stopped!!! 
Running Thread-1-HR-Database
Running Thread-2-Send-Email
Thread: Thread-1-HR-Database, 4
Thread: Thread-2-Send-Email, 4
Thread: Thread-1-HR-Database, 3
Thread: Thread-2-Send-Email, 3
Thread: Thread-1-HR-Database, 2
Thread: Thread-2-Send-Email, 2
Thread: Thread-1-HR-Database, 1
Thread: Thread-2-Send-Email, 1
Thread Thread-1-HR-Database exiting.
Thread Thread-2-Send-Email exiting.

Kết quả chương trình trên được giải thích thông qua hình bên dưới:

Ở phần sau, ta sẽ đi tìm hiểu vòng đời của Thread và những hàm cơ bản sử dụng trong Thread

vncoder logo

Theo dõi VnCoder trên Facebook, để cập nhật những bài viết, tin tức và khoá học mới nhất!



Khóa học liên quan

Khóa học: Java

Tổng hợp Bài tập Java có lời giải
Số bài học:
Lượt xem: 17945
Đăng bởi: Admin
Chuyên mục: Java

Lập trình Java cơ bản
Số bài học:
Lượt xem: 40632
Đăng bởi: Admin
Chuyên mục: Java