Thứ Tư, 12 tháng 9, 2018

Java - Đa luồng

Java là một ngôn ngữ lập trình Java đa luồng có nghĩa là chúng ta có thể phát triển chương trình đa luồng bằng cách sử dụng Java. Một chương trình đa luồng chứa hai hoặc nhiều phần có thể chạy đồng thời và mỗi phần có thể xử lý một nhiệm vụ khác cùng lúc để tận dụng tối ưu các tài nguyên có sẵn đặc biệt khi máy tính của bạn có nhiều CPU.

Theo định nghĩa, đa nhiệm là khi nhiều tiến trình chia sẻ các tài nguyên xử lý thông thường như một CPU. Đa luồng mở rộng ý tưởng đa nhiệm vào các ứng dụng mà bạn có thể chia nhỏ các hoạt động cụ thể trong một ứng dụng đơn lẻ thành các luồng riêng lẻ. Mỗi luồng có thể chạy song song. Hệ điều hành chia thời gian xử lý không chỉ giữa các ứng dụng khác nhau, mà còn giữa các luồng trong một ứng dụng.

Đa luồng cho phép bạn viết theo cách mà nhiều hoạt động có thể tiến hành đồng thời trong cùng một chương trình.

Vòng đời của một chủ đề

Một luồng đi qua các giai đoạn khác nhau trong vòng đời của nó. Ví dụ, một chuỗi được sinh ra, bắt đầu, chạy, và sau đó chết. Sơ đồ sau đây cho thấy vòng đời hoàn chỉnh của một sợi.

Học lập trình Java
Học lập trình Java

Sau đây là các giai đoạn của vòng đời

Mới - Một chủ đề mới bắt đầu vòng đời của nó trong trạng thái mới. Nó vẫn ở trạng thái này cho đến khi chương trình bắt đầu luồng. Nó cũng được gọi là một chủ đề sinh ra .

Runnable - Sau khi một thread mới được sinh ra, thread sẽ trở thành runnable. Một luồng trong trạng thái này được coi là đang thực hiện nhiệm vụ của nó.

Chờ đợi - Đôi khi, một luồng chuyển sang trạng thái chờ trong khi luồng chờ một chuỗi khác thực hiện một tác vụ. Một luồng chuyển tiếp trở lại trạng thái runnable chỉ khi một luồng khác báo hiệu luồng chờ đợi để tiếp tục thực hiện.

Thời gian chờ đợi - Một chuỗi chạy được có thể nhập trạng thái chờ đã hẹn giờ trong một khoảng thời gian được chỉ định. Một luồng trong trạng thái này chuyển trở lại trạng thái runnable khi khoảng thời gian đó hết hạn hoặc khi sự kiện nó đang chờ xảy ra.

Chấm dứt (Dead) - Một thread runnable vào trạng thái kết thúc khi nó hoàn thành nhiệm vụ của nó hoặc kết thúc bằng cách khác.

Ưu tiên chủ đề

Mỗi chuỗi Java có một ưu tiên giúp hệ điều hành xác định thứ tự trong đó các luồng được lên lịch.

Ưu tiên luồng Java nằm trong khoảng từ MIN_PRIORITY (hằng số 1) và MAX_PRIORITY (hằng số là 10). Theo mặc định, mỗi chuỗi được ưu tiên NORM_PRIORITY (một hằng số là 5).

Các chủ đề có mức độ ưu tiên cao hơn quan trọng hơn đối với một chương trình và nên được phân bổ thời gian xử lý trước các luồng ưu tiên thấp hơn. Tuy nhiên, ưu tiên luồng không thể đảm bảo thứ tự trong đó các luồng thực thi và phụ thuộc rất nhiều vào nền tảng.

Tạo một chủ đề bằng cách thực hiện một giao diện Runnable

Nếu lớp của bạn được dự định để được thực thi như một luồng thì bạn có thể đạt được điều này bằng cách thực hiện một giao diện Runnable . Bạn sẽ cần phải làm theo ba bước cơ bản -

Bước 1
Bước đầu tiên, bạn cần triển khai phương thức run () được cung cấp bởi giao diện Runnable . Phương thức này cung cấp một điểm vào cho luồng và bạn sẽ đặt logic nghiệp vụ hoàn chỉnh của bạn bên trong phương thức này. Sau đây là cú pháp đơn giản của phương thức run () -
public void run( )

Bước 2

Bước thứ hai, bạn sẽ khởi tạo một đối tượng Thread bằng cách sử dụng hàm tạo sau:
Thread(Runnable threadObj, String threadName);

Ở đâu, threadObj là một thể hiện của một lớp thực hiện giao diện Runnable và threadName là tên được gán cho luồng mới.

Bước 3
Khi một đối tượng Thread được tạo ra, bạn có thể bắt đầu nó bằng cách gọi phương thức start () , thực hiện một cuộc gọi đến phương thức run (). Sau đây là cú pháp đơn giản của phương thức start ()

void start();

Thí dụ

Đây là một ví dụ tạo ra một chuỗi mới và bắt đầu chạy nó
class RunnableDemo implements Runnable {
   private Thread t;
   private String threadName;
   
   RunnableDemo( String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   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 ();
      }
   }
}

public class TestThread {

   public static void main(String args[]) {
      RunnableDemo R1 = new RunnableDemo( "Thread-1");
      R1.start();
      
      RunnableDemo R2 = new RunnableDemo( "Thread-2");
      R2.start();
   }   
}
Điều này sẽ tạo ra kết quả sau

Đầu ra

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

Tạo một chủ đề bằng cách mở rộng một lớp Thread

Cách thứ hai để tạo một luồng là tạo một lớp mới mở rộng lớp Thread bằng cách sử dụng hai bước đơn giản sau đây. Cách tiếp cận này cung cấp sự linh hoạt hơn trong việc xử lý nhiều luồng được tạo bằng cách sử dụng các phương thức có sẵn trong lớp Thread.

Bước 1
Bạn sẽ cần phải ghi đè lên phương thức run () có sẵn trong lớp Thread. Phương thức này cung cấp một điểm vào cho luồng và bạn sẽ đặt logic nghiệp vụ hoàn chỉnh của bạn bên trong phương thức này. Sau đây là cú pháp đơn giản của phương thức run ()
public void run( )

Bước 2

Khi đối tượng Thread được tạo, bạn có thể khởi động nó bằng cách gọi phương thức start () , thực hiện một cuộc gọi đến phương thức run (). Sau đây là cú pháp đơn giản của phương thức start ()

void start( );

Thí dụ

Đây là chương trình trước được viết lại để mở rộng Thread
class ThreadDemo extends Thread {
   private Thread t;
   private String threadName;
   
   ThreadDemo( String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   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 ();
      }
   }
}

public class TestThread {

   public static void main(String args[]) {
      ThreadDemo T1 = new ThreadDemo( "Thread-1");
      T1.start();
      
      ThreadDemo T2 = new ThreadDemo( "Thread-2");
      T2.start();
   }   
}
Điều này sẽ tạo ra kết quả sau

Đầu ra

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.

Phương thức chủ đề

Sau đây là danh sách các phương thức quan trọng có sẵn trong lớp Thread.

Sr.No.Phương thức & Mô tả
1công khai void start ()

Khởi động luồng trong một đường dẫn thực thi riêng biệt, sau đó gọi phương thức run () trên đối tượng Thread này.
2công khai void run ()
Nếu đối tượng Thread này được khởi tạo bằng cách sử dụng một mục tiêu Runnable riêng biệt, phương thức run () được gọi trên đối tượng Runnable đó.
3public set void setName (Tên chuỗi)

Thay đổi tên của đối tượng Thread. Ngoài ra còn có một phương thức getName () để lấy tên.
4public void void setPriority (int priority)

Đặt mức độ ưu tiên của đối tượng Thread này. Các giá trị có thể nằm trong khoảng từ 1 đến 10.
5công thức void setDaemon (boolean on)

Một tham số của true biểu thị Thread này là một chuỗi daemon.
6tham gia void cuối cùng công khai (dài millisec)

Chủ đề hiện tại gọi phương thức này trên một luồng thứ hai, làm cho luồng hiện tại bị chặn cho đến khi chuỗi thứ hai kết thúc hoặc số mili giây được chỉ định vượt qua.
7ngắt khoảng trống công cộng ()
Ngắt chuỗi này, khiến nó tiếp tục thực thi nếu nó bị chặn vì bất kỳ lý do gì.
số 8public boolean isAlive ()
Trả về true nếu thread vẫn còn, là bất kỳ thời gian nào sau khi thread được bắt đầu nhưng trước khi nó chạy đến khi hoàn thành.
Các phương thức trước được gọi trên một đối tượng Thread cụ thể. Các phương thức sau trong lớp Thread là tĩnh. Gọi một trong các phương thức tĩnh thực hiện thao tác trên luồng hiện đang chạy.

Sr.No.Phương thức & Mô tả
1năng suất tĩnh công cộng ()

Gây ra luồng đang chạy để sinh ra bất kỳ luồng nào khác có cùng mức độ ưu tiên đang đợi để được lên lịch.
2công cộng tĩnh void ngủ (dài millisec)

Gây ra luồng đang chạy để chặn ít nhất số mili giây được chỉ định.
3công khai static boolean holdLock (Object x)
Trả về true nếu luồng hiện tại giữ khóa trên đối tượng đã cho.
4public static Thread currentThread ()
Trả về một tham chiếu đến luồng hiện đang chạy, là luồng mà gọi phương thức này.
5public static void dumpStack ()

In dấu vết ngăn xếp cho chuỗi hiện đang chạy, điều này rất hữu ích khi gỡ lỗi một ứng dụng đa luồng.

Thí dụ

Chương trình ThreadClassDemo sau đây trình bày một số phương thức của lớp Thread. Hãy xem xét một lớp DisplayMessage thực hiện Runnable
// File Name : DisplayMessage.java
// Create a thread to implement Runnable

public class DisplayMessage implements Runnable {
   private String message;
   
   public DisplayMessage(String message) {
      this.message = message;
   }
   
   public void run() {
      while(true) {
         System.out.println(message);
      }
   }
}
Sau đây là một lớp khác mở rộng lớp Thread
// File Name : GuessANumber.java
// Create a thread to extentd Thread

public class GuessANumber extends Thread {
   private int number;
   public GuessANumber(int number) {
      this.number = number;
   }
   
   public void run() {
      int counter = 0;
      int guess = 0;
      do {
         guess = (int) (Math.random() * 100 + 1);
         System.out.println(this.getName() + " guesses " + guess);
         counter++;
      } while(guess != number);
      System.out.println("** Correct!" + this.getName() + "in" + counter + "guesses.**");
   }
}
Sau đây là chương trình chính, sử dụng các lớp được xác định ở trên
// File Name : ThreadClassDemo.java
public class ThreadClassDemo {

   public static void main(String [] args) {
      Runnable hello = new DisplayMessage("Hello");
      Thread thread1 = new Thread(hello);
      thread1.setDaemon(true);
      thread1.setName("hello");
      System.out.println("Starting hello thread...");
      thread1.start();
      
      Runnable bye = new DisplayMessage("Goodbye");
      Thread thread2 = new Thread(bye);
      thread2.setPriority(Thread.MIN_PRIORITY);
      thread2.setDaemon(true);
      System.out.println("Starting goodbye thread...");
      thread2.start();

      System.out.println("Starting thread3...");
      Thread thread3 = new GuessANumber(27);
      thread3.start();
      try {
         thread3.join();
      } catch (InterruptedException e) {
         System.out.println("Thread interrupted.");
      }
      System.out.println("Starting thread4...");
      Thread thread4 = new GuessANumber(75);
      
      thread4.start();
      System.out.println("main() is ending...");
   }
}
Điều này sẽ tạo ra kết quả sau. Bạn có thể thử ví dụ này một lần nữa và một lần nữa và bạn sẽ nhận được một kết quả khác nhau mỗi lần.

Đầu ra

Starting hello thread...
Starting goodbye thread...
Hello
Hello
Hello
Hello
Hello
Hello
Goodbye
Goodbye
Goodbye
Goodbye
Goodbye
.......

Các khái niệm đa luồng Java chính

Trong khi thực hiện lập trình Đa luồng trong Java, bạn sẽ cần phải có các khái niệm sau đây rất tiện dụng

Đồng bộ hóa chuỗi là gì?

Xử lý thông tin liên lạc

Xử lý deadlock thread

Các hoạt động chủ đề chính

Không có nhận xét nào:

Đăng nhận xét

Lập trình Java - Ngoại lệ

Một ngoại lệ (hoặc sự kiện đặc biệt) là một vấn đề phát sinh trong quá trình thực hiện chương trình. Khi xảy ra Ngoại lệ , luồng bình thường...