hocvietcode.com
  • Trang chủ
  • Học lập trình
    • Lập trình C/C++
    • Lập trình HTML
    • Lập trình Javascript
      • Javascript cơ bản
      • ReactJS framework
      • AngularJS framework
      • Typescript cơ bản
      • Angular
    • Lập trình Mobile
      • Lập Trình Dart Cơ Bản
        • Dart Flutter Framework
    • Cơ sở dữ liệu
      • MySQL – MariaDB
      • Micrsoft SQL Server
      • Extensible Markup Language (XML)
      • JSON
    • Lập trình PHP
      • Lập trình PHP cơ bản
      • Laravel Framework
    • Lập trình Java
      • Java Cơ bản
    • Cấu trúc dữ liệu và giải thuật
    • Lập Trình C# Cơ Bản
    • Machine Learning
  • WORDPRESS
    • WordPress cơ bản
    • WordPress nâng cao
    • Chia sẻ WordPress
  • Kiến thức hệ thống
    • Microsoft Azure
    • Docker
    • Linux
  • Chia sẻ IT
    • Tin học văn phòng
      • Microsoft Word
      • Microsoft Excel
    • Marketing
      • Google Adwords
      • Facebook Ads
      • Kiến thức khác
    • Chia sẻ phần mềm
    • Review công nghệ
    • Công cụ – tiện ích
      • Kiểm tra bàn phím online
      • Kiểm tra webcam online
Đăng nhập
  • Đăng nhập / Đăng ký

Please enter key search to display results.

Home
  • Java Cơ bản
Thread (Luồng) trong Java

Thread (Luồng) trong Java

  • 14-11-2023
  • Toanngo92
  • 0 Comments

Mục lục

  • Giới Thiệu
    • So Sánh Giữa Tiến Trình và Luồng
    • Ứng Dụng và Sử Dụng của Luồng
  • Tạo Threads
    • Hàm khởi tạo và các phương thức lớp Thread
    • Giao diện Runnable
  • Vòng đời của Thread
    • Trạng thái luồng (Thread States)
    • Trạng thái chạy được (Runnable State)
    • Trạng thái bị chặn (Blocked State)
    • Trạng thái Chờ
  • Các phương thức lớp Thread
    • Phương thức start()
    • Phương thức run()
    • Phương thức sleep()
    • Phương thức interrupt()
  • Quản lý luồng
    • Sự Cần Thiết của Ưu Tiên Luồng
    • Các Loại Ưu Tiên Luồng
    • Phương thức setPriority()
    • Phương thức getPriority()
  • Luồng Daemon
    • Sự Cần Thiết của Các Luồng Daemon

Giới Thiệu

Một tiến trình là một chương trình đang thực thi. Mỗi tiến trình có các tài nguyên thời gian chạy riêng biệt của mình, như dữ liệu riêng, biến và không gian bộ nhớ riêng. Các tài nguyên thời gian chạy này tạo nên một môi trường thực thi cho các tiến trình bên trong một chương trình. Do đó, mỗi tiến trình có một môi trường thực thi tự chủ để chạy độc lập. Mỗi tiến trình thực hiện nhiều công việc cùng một lúc và mỗi công việc được thực hiện bởi các luồng riêng biệt. Một luồng không gì khác ngoài, đơn vị cơ bản mà hệ điều hành cấp phát thời gian xử lý. Một luồng là thực thể trong một tiến trình có thể được lên lịch để thực thi. Một tiến trình bắt đầu với một luồng duy nhất, thường được gọi là luồng chính, mặc định hoặc chính. Vì vậy, một tiến trình lại chứa một hoặc nhiều luồng.

Một luồng có các đặc điểm sau:

Một luồng có bộ tài nguyên thời gian chạy cơ bản đầy đủ của mình để chạy độc lập.
Một luồng là đơn vị nhỏ nhất của mã thực thi trong ứng dụng thực hiện một công việc cụ thể.
Nhiều luồng có thể được thực thi cùng một lúc, tạo điều kiện thực hiện nhiều công việc của một ứng dụng duy nhất đồng thời.

So Sánh Giữa Tiến Trình và Luồng

Nhiều luồng cho phép truy cập vào cùng một phần bộ nhớ, trong khi tiến trình không thể truy cập trực tiếp vào bộ nhớ của một tiến trình khác.

Một số sự tương đồng và khác biệt giữa tiến trình và luồng như sau:

Tương Đồng

  • Các luồng chia sẻ một đơn vị xử lý trung ương và chỉ có một luồng hoạt động (đang chạy) vào một thời điểm.
  • Các luồng bên trong tiến trình thực hiện theo thứ tự.
  • Một luồng có thể tạo ra các luồng con hoặc luồng phụ.
  • Nếu một luồng bị chặn, một luồng khác có thể chạy.

Khác Biệt

  • Khác với tiến trình, các luồng không độc lập lẫn nhau.
  • Khác với tiến trình, tất cả các luồng có thể truy cập mọi địa chỉ trong nhiệm vụ.

Ứng Dụng và Sử Dụng của Luồng

Trong Java, một Luồng hỗ trợ xử lý song song của nhiều nhiệm vụ.
Một số ứng dụng của luồng như sau:

Chạy âm thanh và hiển thị hình ảnh đồng thời.

Tạo Threads

Một cách dễ dàng để tạo một luồng mới là kế thừa một lớp từ lớp java.lang.Thread. Lớp này bao gồm các phương thức và constructors, giúp thực hiện khái niệm lập trình đồng thời trong Java. Điều này được sử dụng để tạo các ứng dụng có thể thực hiện nhiều nhiệm vụ đồng thời.

Quy trình từng bước để tạo một luồng mới bằng cách mở rộng lớp Thread được thảo luận ở đây.

Bước 1: Tạo Một Lớp Con

Khai báo một lớp là lớp con của lớp Thread được định nghĩa trong gói java.lang.

Đoạn mã 1 dưới đây thể hiện việc tạo lớp con. Lớp MyThread sẽ kế thừa các khả năng của lớp Thread và cho phép thực hiện các nhiệm vụ đa luồng.

class MyThread extends Thread { 
     // Kế thừa từ lớp Thread
    // Định nghĩa lớp
}

Bước 2: Ghi đè phương thức run()

Bên trong lớp con, ghi đè phương thức run() được định nghĩa trong lớp Thread. Đoạn mã trong phương thức run() xác định chức năng cần thiết để luồng thực thi. Phương thức run() trong một luồng tương tự như phương thức main() trong một ứng dụng.

Đoạn mã 2 hiển thị cách triển khai của phương thức run().

class MyThread extends Thread { // Kế thừa từ lớp Thread
    // Định nghĩa lớp

    public void run() { // Ghi đè phương thức run()
        // Triển khai
    }
}

Bước 3: Khởi động luồng

Phương thức main() tạo một đối tượng của lớp kế thừa từ lớp Thread. Sau đó, phương thức start() được gọi trên đối tượng để bắt đầu luồng. Phương thức start() sẽ đặt đối tượng Luồng vào trạng thái chạy. Phương thức start() của một luồng gọi phương thức run(), nơi cung cấp các tài nguyên cần thiết để chạy luồng.

public static void main(String[] args) {
    // Tạo đối tượng của lớp con
    MyThread myThread = new MyThread();

    // Khởi động luồng bằng cách gọi start()
    myThread.start();
}

Hàm khởi tạo và các phương thức lớp Thread

Bảng dưới mô tả Constructor lớp Thread

ConstructorMô tả
Thread()Constructor mặc định
Thread(Runnable objRun)Tạo một đối tượng Thread mới, trong đó objRun là đối tượng, phương thức run() của nó được gọi
Thread(Runnable objRun, String threadName)Tạo một đối tượng Thread mới có tên, trong đó objRun là đối tượng, phương thức run() của nó được gọi và threadName là tên của luồng sẽ được tạo
Thread(String threadName)Tạo một đối tượng Thread mới với threadName là tên của luồng sẽ được tạo
Thread(ThreadGroup group, Runnable objRun)Tạo một đối tượng Thread mới, trong đó group là nhóm luồng và objRun là đối tượng, phương thức run() của nó được gọi
Thread(ThreadGroup group, Runnable objRun, String threadName)Tạo một đối tượng Thread mới có tên, trong đó group là nhóm luồng, objRun là đối tượng, phương thức run() của nó được gọi và threadName là tên của luồng sẽ được tạo
Thread(ThreadGroup group, Runnable objRun, String threadName, long stackSize)Tạo một đối tượng Thread mới có tên, trong đó group là nhóm luồng, objRun là đối tượng, phương thức run() của nó được gọi, threadName là tên của luồng sẽ được tạo và stackSize là kích thước của ngăn xếp cho luồng

Lớp Thread cung cấp một số phương thức để làm việc với chương trình đa luồng, mô tả ở bảng dưới:

MethodMô tả
static int activeCount()Trả về số lượng luồng đang hoạt động trong số luồng hiện tại trong chương trình
static Thread currentThread()Trả về tham chiếu đến luồng đang thực thi hiện tại
ThreadGroup getThreadGroup()Trả về nhóm luồng mà luồng này thuộc về
static boolean interrupted()Kiểm tra xem luồng hiện tại đã bị gián đoạn hay chưa
boolean isAlive()Kiểm tra xem luồng này còn sống hay không
boolean isInterrupted()Kiểm tra xem luồng này đã bị gián đoạn hay chưa
void join()Đợi cho đến khi luồng này kết thúc
void setName(String name)Đặt tên mới cho luồng này để bằng với đối số name

Ví dụ:

package demo;

// NamedThread is created as a subclass of the class Thread
public class NamedThread extends Thread {
    String name;

    // This method of Thread class is overridden to specify the action that will be done
    // when the thread begins execution
    public void run() {
        // Will store the number of threads
        int count = 0;

        while (count < 4) {
            // Display the number of threads
            System.out.println(Thread.activeCount());

            // Display the name of the currently running thread
            name = Thread.currentThread().getName();
            count++;

            System.out.println(name);

            if (name.equals("Thread-0")) {
                System.out.println("Marimba");
            } else {
                System.out.println("Jini");
            }

            try {
                // Sleep for a short duration to allow other threads to run
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        NamedThread objNamedThread = new NamedThread();
        objNamedThread.setName("Thread-0");

        // Display the status of the thread, whether alive or not
        System.out.println(Thread.currentThread().isAlive());
        System.out.println(objNamedThread.isAlive());

        // Invokes the start method which in turn will call
        // run and begin thread execution
        objNamedThread.start();

        // Display the status of the thread after it has started
        System.out.println(Thread.currentThread().isAlive());
        System.out.println(objNamedThread.isAlive());
    }
}

Lưu ý: Lập trình đồng thời (Concurrent Programming)

Lập trình đồng thời là quá trình chạy nhiều nhiệm vụ cùng một lúc.

Trong Java, có thể thực hiện đồng thời một phương thức được gọi và các câu lệnh sau lời gọi phương thức mà không cần đợi phương thức được gọi kết thúc.

Phương thức được gọi chạy độc lập và đồng thời với chương trình gọi, và có thể chia sẻ biến, dữ liệu và các thành phần khác với nó.

Giao diện Runnable

Giao diện Runnable được thiết kế để cung cấp một tập hợp các quy tắc chung cho các đối tượng muốn thực hiện mã khi một luồng đang hoạt động. Một cách khác để tạo một luồng mới là bằng cách triển khai giao diện Runnable. Phương pháp này có thể được sử dụng vì Java không cho phép đa kế thừa lớp. Do đó, tùy thuộc vào yêu cầu cụ thể, cả hai phương pháp có thể được sử dụng để tạo luồng trong Java.

Bước 1: Triển khai giao diện Runnable

Khai báo một lớp triển khai giao diện Runnable. Đoạn mã Snippet 5 triển khai giao diện Runnable.

// Khai báo một lớp triển khai giao diện Runnable
class MyRunnable implements Runnable {
}

Bước 2: Triển khai phương thức run()

Giao diện Runnable định nghĩa một phương thức run(), chứa mã sẽ được thực thi bởi đối tượng luồng. Lớp triển khai giao diện Runnable nên ghi đè phương thức run(). Đoạn mã Snippet 6 triển khai phương thức run().

// Khai báo một lớp triển khai giao diện Runnable
class MyRunnable implements Runnable {
    // Ghi đè phương thức run()
    public void run() {
        // Thực hiện công việc của luồng
    }
}

Bước 3: Bắt đầu luồng

Trong phương thức main(), tạo một đối tượng của lớp triển khai giao diện Runnable. Sau đó, chuyển đối tượng này vào hàm tạo của lớp Thread để tạo một đối tượng luồng. Cuối cùng, gọi phương thức start() trên đối tượng luồng để bắt đầu luồng.

// Phương thức main
public static void main(String[] args) {
    // Tạo đối tượng của lớp triển khai Runnable
    MyRunnable myRunnable = new MyRunnable();

    // Chuyển đối tượng vào hàm tạo của lớp Thread
    Thread myThread = new Thread(myRunnable);

    // Gọi phương thức start() để bắt đầu luồng
    myThread.start();
}

Ví dụ triển khai hoàn thiện:

Tạo lớp NamedThread

package test;

// NamedThread is created to implement the interface Runnable
class NamedThread implements Runnable {

    // This will store the name of the thread
    String name;

    // The method of Runnable is implemented to specify the action
    // that will be done when the thread begins execution.
    public void run() {
        int count = 0; // Will store the number of threads

        while (count < 3) {
            name = Thread.currentThread().getName();
            System.out.println(name);
            count++;
        }
    }
}

Tạo lớp MainTest

public class MainTest {
    public static void main(String[] args) {
        NamedThread objNewThread = new NamedThread();
        Thread newThread = new Thread(objNewThread);
        newThread.start();
    }
}

Output:

Thread-0
Thread-0
Thread-0

Vòng đời của Thread

Trạng thái luồng (Thread States)

Một luồng có thể tồn tại trong nhiều trạng thái khác nhau, chẳng hạn như new (mới), runnable (chạy được), blocked (bị chặn), waiting (đang đợi), và terminated (kết thúc), tùy thuộc vào các giai đoạn khác nhau trong chương trình. Khi một luồng mới được tạo, nó ở trạng thái mới (new thread) và chưa được kích hoạt (alive).

Trong trạng thái này, đó là một đối tượng Luồng mới không chứa bất kỳ nguồn tài nguyên hệ thống nào đã được phân bổ. Do đó, luồng ở trạng thái “luồng mới” cho đến khi phương thức start() được gọi trên nó. Khi một luồng ở trong trạng thái này, bạn chỉ có thể bắt đầu hoặc dừng luồng đó. Gọi bất kỳ phương thức nào khác trước khi bắt đầu luồng sẽ gây ra IllegalThreadStateException.

Hình dưới mô tả trạng thái new của luồng

Trạng thái này xảy ra khi biến thể hiện Thread vừa được tạo:

Thread thObj = new Thread();

Trạng thái chạy được (Runnable State)

Một luồng mới có thể ở trạng thái chạy được khi phương thức start() được gọi trên nó. Một luồng ở trạng thái này là đang chạy. Luồng có thể chuyển sang trạng thái chạy được từ trạng thái đang chạy hoặc bị chặn.

Các luồng được ưu tiên vì trong một hệ thống có một bộ xử lý duy nhất, không thể thực hiện tất cả các luồng chạy được cùng một lúc. Trong trạng thái chạy được, một luồng có đủ điều kiện để chạy, nhưng có thể không chạy ngay lập tức tùy thuộc vào ưu tiên của luồng đó. Khi một luồng chạy được trở nên đủ điều kiện để chạy, nó thực thi các chỉ thị trong phương thức run() của nó.

Hình dưới mô tả trạng thái Runnable

Trạng thái này xảy ra khi biến thể hiện Thread gọi phương thức start():

Thread thObj = new Thread();
thObj.start();

Lưu ý: Trạng thái này được gọi là chạy được vì mặc dù luồng có thể không chạy, nhưng luồng đã được cấp phát tất cả các tài nguyên để chạy.

Lập lịch là một thành phần trong Java gán ưu tiên cho các luồng để thực hiện theo yêu cầu.

Trạng thái bị chặn (Blocked State)

Blocked State (Trạng thái bị chặn) là một trong những trạng thái mà một luồng:

  • Đang sống nhưng hiện không thể chạy vì đã bị chặn do một số hoạt động khác.
  • Không chạy được nhưng có thể quay lại trạng thái chạy được sau khi có được giám sát hoặc khóa.

Một luồng trong trạng thái bị chặn đang đợi để thực hiện các hoạt động trên tài nguyên hoặc đối tượng đang được xử lý bởi một luồng khác. Một luồng đang chạy chuyển sang trạng thái bị chặn khi phương thức sleep(), wait(), hoặc suspend() được gọi trên nó.

Ghi chú: Khóa hoặc giám sát là một hộp ảo chứa một đối tượng. Hộp ảo này chỉ cho phép một luồng duy nhất vào để nó có thể thao tác trên đối tượng. Bất kỳ luồng nào muốn chia sẻ nguồn lực hoặc đối tượng phải nhận khóa.

Trạng thái Chờ

Một luồng ở trong trạng thái này khi nó đang chờ đợi một luồng khác giải phóng nguồn lực cho nó. Khi hai hoặc nhiều luồng chạy song song và chỉ có một luồng giữ nguồn lực suốt thời gian, các luồng khác cuối cùng sẽ đợi luồng này giải phóng nguồn lực cho chúng. Trong trạng thái này, một luồng vẫn còn sống nhưng không chạy.

Một cuộc gọi đến phương thức wait() đặt một luồng vào trạng thái chờ đợi này. Gọi phương thức notify() hoặc notifyAll() đưa luồng từ trạng thái chờ đợi đến trạng thái có thể chạy được.

Hình dưới mô tả trạng thái chờ

Chú ý: Nếu phương thức start() được gọi trên một trạng thái đã kết thúc, sẽ ném một ngoại lệ thời gian chạy.

Các phương thức lớp Thread

Lớp Thread trong Java bao gồm nhiều phương thức có thể được sử dụng để thao tác với các luồng.

Tất cả các luồng đều có một tên được liên kết với chúng. Đôi khi, cần phải lấy tên của một luồng cụ thể. Phương thức getName() giúp lấy tên của luồng hiện tại.

Ví dụ:

public class ThreadGetNameExample {
    public static void main(String[] args) {
        // Creating two threads
        Thread thread1 = new MyThread("Thread 1");
        Thread thread2 = new MyThread("Thread 2");

        // Start the threads
        thread1.start();
        thread2.start();
    }
}

class MyThread extends Thread {
    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        // Display the name of the current thread
        System.out.println("Thread Name: " + Thread.currentThread().getName());
    }
}

Output:

Thread Name: Thread 1
Thread Name: Thread 2

Ghi chú: Phương thức setName() gán một tên cho một đối tượng luồng. Tên được truyền như một đối số cho phương thức.

public final void setName(String name)

Ở đây,

  • name là một đối số kiểu String được truyền vào phương thức setName().

Phương thức start()

Một luồng mới được tạo sẽ ở trạng thái đợi đến khi phương thức start() được gọi. Phương thức start() cấp phát các tài nguyên hệ thống cần thiết để chạy luồng và thực thi phương thức run() của đối tượng mục tiêu của nó.

Khi gọi phương thức start(), các hành động sau xảy ra:

  • Một luồng thực thi mới được khởi động.
  • Luồng chuyển từ trạng thái luồng mới sang trạng thái có thể chạy (runnable).

Ví dụ:

Thread thObj = new Thread();
thObj.start();

Phương thức run()

Cuộc sống của một luồng bắt đầu khi phương thức run() được gọi. Các đặc điểm của phương thức run() như sau:

  • Nó là một phương thức công cộng (public).
  • Không chấp nhận đối số nào.
  • Không trả về bất kỳ giá trị nào.
  • Không ném bất kỳ ngoại lệ nào.

Phương thức run() chứa các chỉ thị, sẽ được thực thi khi phương thức start() được gọi.

Ví dụ:

// Khai báo một lớp triển khai giao diện Runnable
class MyRunnable implements Runnable {
    // Ghi đè phương thức run()
    public void run() {
        // Thực hiện công việc của luồng
    }
}

Phương thức sleep()

Phương thức sleep() có các đặc điểm sau:

  • Nó tạm dừng việc thực thi của luồng hiện tại trong một khoảng thời gian nhất định.
  • Nó làm cho thời gian xử lý sẵn có để các luồng khác của ứng dụng hoặc các ứng dụng khác có thể chạy trên hệ thống máy tính.
  • Nó dừng thực thi nếu luồng hiện tại trong khoảng thời gian được chỉ định tính bằng mili giây hoặc nanogian.
  • Nó ném ra một ngoại lệ InterruptedException khi bị gián đoạn bằng cách sử dụng phương thức interrupt().

Cú pháp:

void sleep(long mills);

Ví dụ:

public class SleepMethodExample {
    public static void main(String[] args) {
        for (int i = 1; i <= 5; i++) {
            System.out.println("Iteration " + i);

            try {
                // Sleep for 1 second (1000 milliseconds)
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.println("Main thread finished.");
    }
}

Phương thức interrupt()

Phương thức interrupt() gián đoạn luồng. Phương thức này yêu cầu luồng dừng lại ngay cả trước khi hoàn thành nhiệm vụ. Phương thức interrupt() có các đặc điểm sau.

  • Một luồng bị gián đoạn có thể chấm dứt, đợi cho một nhiệm vụ khác hoặc tiếp tục sang bước tiếp theo tùy thuộc vào yêu cầu của ứng dụng.
  • Nó không gián đoạn hoặc dừng một luồng đang chạy; thay vào đó, nó ném một InterruptedException nếu luồng bị chặn, để nó thoát khỏi trạng thái chặn,
  • Nếu luồng bị chặn bởi các phương thức wait(), join() hoặc sleep(), nó nhận một Interrupted=xception, do đó kết thúc phương thức chặn trước thời gian dự kiến.

Cú pháp:

public void interrupt()

Lưu ý: Một luồng có thể tự gián đoạn chính nó. Khi một luồng không tự gián đoạn, phương thức checkAccess() được gọi. Phương thức này kiểm tra xem luồng hiện tại có đủ quyền để sửa đổi luồng hay không. Trong trường hợp quyền không đủ, bảo vệ an toàn ném ra một SecurityException để chỉ ra vi phạm an toàn.

Ví dụ:

public class InterruptExample {
    public static void main(String[] args) {
        Thread myThread = new MyThread();
        myThread.start();

        // Main thread sleeps for 3 seconds
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // Interrupt the MyThread
        myThread.interrupt();
    }
}

class MyThread extends Thread {
    @Override
    public void run() {
        try {
            // Thread sleeps for a long time (simulating a blocking operation)
            while (true) {
                System.out.println("Thread is running...");
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            // Handle the InterruptedException
            System.out.println("Thread interrupted! Exiting...");
        }
    }
}

Quản lý luồng

Trong các hoạt động hàng ngày của chúng ta, cần phải gán các mức độ quan trọng khác nhau cho các nhiệm vụ khác nhau. Quyết định được đưa ra để đạt được kết quả tốt nhất có thể. Ví dụ, khi quyết định giữa việc đi làm và xem truyền hình, việc đi làm được ưu tiên hơn so với việc xem truyền hình.
Điều này bởi vì việc đi làm quan trọng hơn đối với lợi ích tài chính của người đó so với việc giải trí đơn thuần. Tương tự, trong lập trình Java, việc ưu tiên các luồng theo mức quan trọng là cần thiết.

Luồng là các thực thể tự thực thi bên trong một chương trình. Trong một chương trình duy nhất, có thể có nhiều luồng thực thi độc lập lẫn nhau. Tuy nhiên, đôi khi có thể xảy ra tình huống mà một tài nguyên thực thi cụ thể phải được chia sẻ bởi nhiều luồng đang chạy đồng thời. Điều này buộc các luồng khác đang chạy phải chuyển sang trạng thái chặn. Do đó, trong những tình huống như vậy, cần có một sự kiểm soát hoặc quản lý nội bộ của các luồng để chúng được thực thi đồng thời.

Hình dưới mô tả chương trình thực thi đa luồng

Lưu ý: Ví dụ về một trình xử lý từ vựng; có nhiều luồng đang chạy cùng một lúc, như các luồng để chấp nhận từ vựng được gõ, tự động lưu và kiểm tra chính tả. Do đó, cần quản lý tài nguyên hệ thống một cách hiệu quả để chạy tất cả các nhiệm vụ mà không có xung đột. Khi ứng dụng được đóng, tất cả các luồng nên được chấm dứt đồng thời.

Sự Cần Thiết của Ưu Tiên Luồng

Trong khi tạo ứng dụng đa luồng, có thể xảy ra tình huống một luồng đã chạy và bạn muốn chạy một luồng khác quan trọng hơn. Đây là nơi ưu tiên luồng đóng một vai trò quan trọng. Ưu tiên được sử dụng để diễn đạt sự quan trọng của các luồng khác nhau. Ưu tiên đóng một vai trò quan trọng khi có sự tranh chấp nặng nề giữa các luồng cố gắng có cơ hội thực thi. Quá trình ưu tiên này được quản lý bởi trình lên lịch mà gán ưu tiên cho các luồng tương ứng.

Lưu ý: Ưu tiên luồng tương tự như cuộc sống hàng ngày của chúng ta, nơi chúng ta phải ưu tiên lịch trình hoặc quyết định của mình dựa trên một số yếu tố để mọi công việc được thực hiện theo đúng ưu tiên của chúng.

Các Loại Ưu Tiên Luồng

Ưu tiên luồng giúp lên lịch trình luồng quyết định luồng nào được chạy. Ưu tiên cũng giúp hệ điều hành quyết định lượng tài nguyên cần được phân bổ cho mỗi luồng. Ưu tiên luồng là số nguyên từ Thread.MIN_PRIORITY đến Thread.MAX_PRIORITY. Số càng cao, ưu tiên càng cao. Luồng có ưu tiên cao hơn sẽ nhận được nhiều thời gian CPU hơn so với luồng có ưu tiên thấp hơn. Ưu tiên luồng trong Java là các hằng số được định nghĩa trong lớp Thread:

  • Thread.MAX_PRIORITY: Giá trị hằng số là 10, có độ ưu tiên cao nhất.
  • Thread.NORM_PRIORITY: Giá trị hằng số là 5, đây là độ ưu tiên mặc định.
  • Thread.MIN_PRIORITY: Giá trị hằng số là 1, có độ ưu tiên thấp nhất.

Lưu ý: Mọi luồng có độ ưu tiên mặc định là NORM_PRIORITY.

Phương thức setPriority()

Một luồng mới được tạo sẽ kế thừa độ ưu tiên từ luồng đã tạo nó. Để thay đổi độ ưu tiên của một luồng, ta sử dụng phương thức setPriority(). Phương thức setPriority() thay đổi độ ưu tiên hiện tại của một luồng. Phương thức setPriority() chấp nhận giá trị nguyên từ 1 đến 10.

Cú pháp:

public final void setPriority(int newPriority)

Ví dụ:

Tạo lớp MyThread

class MyThread extends Thread {
    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        System.out.println("Thread " + getName() + " is running.");
    }
}

Tạo lớp ThreadPriorityExample

public class ThreadPriorityExample {
    public static void main(String[] args) {
        Thread thread1 = new MyThread("Thread 1");
        Thread thread2 = new MyThread("Thread 2");

        // Display the default priorities of the threads
        System.out.println("Thread 1 Default Priority: " + thread1.getPriority());
        System.out.println("Thread 2 Default Priority: " + thread2.getPriority());

        // Set new priorities for the threads
        thread1.setPriority(Thread.MIN_PRIORITY);
        thread2.setPriority(Thread.MAX_PRIORITY);

        // Start the threads
        thread1.start();
        thread2.start();

        // Display the updated priorities of the threads
        System.out.println("Thread 1 Updated Priority: " + thread1.getPriority());
        System.out.println("Thread 2 Updated Priority: " + thread2.getPriority());
    }
}

Output:

Thread 1 Default Priority: 5
Thread 2 Default Priority: 5
Thread 1 Updated Priority: 1
Thread 2 Updated Priority: 10

Phương thức getPriority()

Phương thức getPriority() giúp lấy giá trị độ ưu tiên hiện tại của một luồng. Điều này giúp truy vấn để biết giá trị độ ưu tiên hiện tại của luồng đang chạy để đảm bảo rằng luồng đang chạy ở mức độ ưu tiên yêu cầu.

Cú pháp:

public final int getPriority()

Ví dụ:

public class ThreadPriorityExample {
    public static void main(String[] args) {
        Thread thread1 = new MyThread("Thread 1");
        Thread thread2 = new MyThread("Thread 2");

        // Start the threads
        thread1.start();
        thread2.start();

        // Display the priorities of the threads
        System.out.println("Thread 1 Priority: " + thread1.getPriority());
        System.out.println("Thread 2 Priority: " + thread2.getPriority());
    }
}

class MyThread extends Thread {
    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        System.out.println("Thread " + getName() + " is running.");
    }
}

Output:

Thread 1 is running.
Thread 2 is running.
Thread 1 Priority: 5
Thread 2 Priority: 5

Luồng Daemon

Một luồng daemon chạy liên tục để thực hiện một dịch vụ, mà không có bất kỳ kết nối nào với trạng thái tổng thể của chương trình. Nói chung, các luồng chạy mã hệ thống là ví dụ tốt về luồng daemon.

Các đặc điểm của các luồng daemon như sau:

  • Chúng hoạt động ở nền, cung cấp dịch vụ cho các luồng khác.
  • Chúng hoàn toàn phụ thuộc vào các luồng người dùng.

Lúc một luồng chết, máy ảo Java sẽ dừng lại và chỉ có luồng daemon là còn sống.

Lớp Thread có hai phương thức liên quan đến các luồng daemon:

setDaemon(boolean value): Phương thức này chuyển đổi một luồng người dùng thành luồng daemon. Nó nhận một giá trị boolean làm đối số. Để đặt một luồng làm luồng daemon, phương thức setDaemon() được gọi với giá trị true. Mặc định, mỗi luồng là luồng người dùng trừ khi nó được đặt là luồng daemon trước đó.

Cú pháp:

void setDaemon(boolean val)

isDaemon(): Phương thức này xác định xem một luồng có phải là luồng daemon hay không. Nó trả về true nếu luồng này là luồng daemon, ngược lại trả về false.

Cú pháp:

boolean isDaemon()

Chú ý: Ví dụ về các luồng daemon bao gồm luồng thu gom rác và luồng xử lý sự kiện chuột cho một chương trình Java. Ngược lại, các luồng người dùng là các luồng mặc định quan trọng đối với việc thực thi của chương trình.

Ví dụ:

public class DaemonThreadExample {
    public static void main(String[] args) {
        // Creating a daemon thread
        Thread daemonThread = new MyDaemonThread();
        
        // Setting the thread as daemon
        daemonThread.setDaemon(true);
        
        // Start the daemon thread
        daemonThread.start();

        // Main thread (non-daemon) continues its execution
        for (int i = 0; i < 5; i++) {
            System.out.println("Main thread is running...");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.println("Main thread finished.");
    }
}

class MyDaemonThread extends Thread {
    @Override
    public void run() {
        // Daemon thread runs in the background
        while (true) {
            System.out.println("Daemon thread is running...");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Sự Cần Thiết của Các Luồng Daemon

Các nhiệm vụ thực hiện bởi các luồng Daemon bao gồm:

  • Các luồng Daemon là nhà cung cấp dịch vụ cho các luồng khác đang chạy trong cùng một quy trình.
  • Các luồng Daemon được thiết kế như các luồng nền cấp thấp thực hiện một số công việc như sự kiện chuột cho chương trình Java.
  • Chúng thường được sử dụng cho các tác vụ nền, chẳng hạn như thu thập và giám sát rác.

Chú ý: Một luồng có thể được đặt là Daemon khi lập trình viên không muốn chương trình chính phải đợi cho đến khi một luồng kết thúc.

Bài tập

1. Viết một chương trình sử dụng thread để tính tổng của một mảng số nguyên.
2. Viết một chương trình sử dụng thread để in ra các số nguyên từ 1 đến 10 theo thứ tự ngẫu nhiên.
3. Viết một chương trình sử dụng thread để tạo ra một bộ đếm ngược từ 10 đến 1.
4. Viết một chương trình sử dụng thread để tạo ra một hàng đợi và thực hiện các thao tác thêm và xóa phần tử khỏi hàng đợi.
5. Viết một chương trình sử dụng thread để tạo ra một bộ đếm thời gian và in ra thời gian đã trôi qua.
6. Tạo chương trình với 2 thread Thead1 và Thread2.
trong thead 1, lưu trữ mảng số:
int[] numList = [1,3,4,6,7];
Thread 2 sử dụng để cộng 10 đơn vị cho phần tử mảng của thread 1
Tạo lớp Main để chạy 2 thread và in ra màn hình

Bài viết liên quan:

Các tính năng nâng cao mới trong Java
Logging API, Resource Bundles, Networking trong Java
Cấu trúc dữ liệu Java
Biểu thức lambda nâng cao
Design Pattern (Mẫu thiết kế) và các tính năng nâng cao khác
Các tính năng nâng cao của JDBC API
Java JDBC API
Đa luồng (multithreading) và đa nhiệm (Concurrency)
Stream (luồng) và xử lý File trong Java
Generic trong Java
Java Utility API, các Collections trong Java
Tìm hiểu thêm Package, regular expression trong Java

THÊM BÌNH LUẬN Cancel reply

Dịch vụ thiết kế Wesbite

NỘI DUNG MỚI CẬP NHẬT

4. KIỂM THỬ VÀ TRIỂN KHAI HỆ THỐNG

2. PHÂN TÍCH VÀ ĐẶC TẢ HỆ THỐNG

3. THIẾT KẾ HỆ THỐNG

1. TỔNG QUAN KIẾN THỨC THỰC HÀNH TRIỂN KHAI DỰ ÁN CÔNG NGHỆ THÔNG TIN

Hướng dẫn tự cài đặt n8n comunity trên CyberPanel, trỏ tên miền

Giới thiệu

hocvietcode.com là website chia sẻ và cập nhật tin tức công nghệ, chia sẻ kiến thức, kỹ năng. Chúng tôi rất cảm ơn và mong muốn nhận được nhiều phản hồi để có thể phục vụ quý bạn đọc tốt hơn !

Liên hệ quảng cáo: [email protected]

Kết nối với HỌC VIẾT CODE

© hocvietcode.com - Tech888 Co .Ltd since 2019

Đăng nhập

Trở thành một phần của cộng đồng của chúng tôi!
Registration complete. Please check your email.
Đăng nhập bằng google
Đăng kýBạn quên mật khẩu?

Create an account

Welcome! Register for an account
The user name or email address is not correct.
Registration confirmation will be emailed to you.
Log in Lost your password?

Reset password

Recover your password
Password reset email has been sent.
The email could not be sent. Possible reason: your host may have disabled the mail function.
A password will be e-mailed to you.
Log in Register
×