JavaRush /Blog Java /Random-VI /Đa luồng: Phương thức lớp luồng làm gì

Đa luồng: Phương thức lớp luồng làm gì

Xuất bản trong nhóm
Xin chào! Hôm nay chúng ta tiếp tục nói về đa luồng. Chúng ta hãy xem lớp Thread và cách hoạt động của một số phương thức của nó. Trước đây, khi nghiên cứu các phương thức của lớp, chúng ta thường viết đơn giản như thế này: “tên của phương thức” -> “nó làm gì”.
Multithreading: các phương thức của lớp Thread làm gì - 1
Điều này sẽ không hoạt động với các phương thức Thread :) Logic của chúng phức tạp hơn và không thể hiểu được nếu không có nhiều ví dụ.

Phương thức Thread.start()

Hãy bắt đầu với sự lặp lại. Như bạn có thể nhớ, bạn có thể tạo một luồng bằng cách kế thừa lớp của bạn từ lớp đó Threadvà ghi đè phương thức trong đó run(). Nhưng tất nhiên, nó sẽ không tự bắt đầu. Để làm điều này, chúng ta gọi phương thức trên đối tượng của mình start(). Đa luồng: các phương thức của lớp Thread làm gì - 2Hãy nhớ lại ví dụ ở bài giảng trước:

public class MyFirstThread extends Thread {

   @Override
   public void run() {
       System.out.println("Выполнен поток " + getName());
   }
}


public class Main {

   public static void main(String[] args) {

       for (int i = 0; i < 10; i++) {
           MyFirstThread thread = new MyFirstThread();
           thread.start();
       }
   }
}
Xin lưu ý: để bắt đầu một chủ đề, bạn phải gọi phương thức đặc biệtstart(), không phảirun()! Đây là một lỗi rất dễ mắc phải, đặc biệt khi mới học đa luồng. Nếu trong ví dụ của chúng tôi, bạn gọi phương thức của đối tượngrun()thay vìstart()thì kết quả sẽ như sau:

public class Main {

   public static void main(String[] args) {

       for (int i = 0; i < 10; i++) {
           MyFirstThread thread = new MyFirstThread();
           thread.run();
       }
   }
}
Thread-0 đã thực thi Thread-1 đã thực thi Thread-2 đã thực thi Thread-3 đã thực thi Thread-4 đã thực thi Thread-5 đã thực thi Thread-6 đã thực thi Thread-7 đã thực thi Thread-8 đã thực hiện Thread-9 đã thực thi Nhìn vào trình tự đầu ra: mọi thứ diễn ra theo đúng thứ tự. Kỳ lạ phải không? Chúng tôi không quen với điều này, bởi vì chúng tôi đã biết rằng thứ tự khởi chạy và thực thi các luồng được xác định bởi siêu trí tuệ bên trong hệ điều hành của chúng tôi - bộ lập lịch luồng. Có lẽ tôi chỉ may mắn? Tất nhiên, đó không phải là vấn đề may mắn. Bạn có thể xác minh điều này bằng cách chạy chương trình thêm một vài lần nữa. Vấn đề là việc gọi một phương thức trực tiếprun()không liên quan gì đến đa luồng. Trong trường hợp này, chương trình sẽ được thực thi trong luồng chính - luồng trong đó phương thức được thực thimain(). Nó sẽ chỉ xuất ra 10 dòng tuần tự tới bảng điều khiển và thế là xong. Không có 10 chủ đề sẽ bắt đầu. Vì vậy, hãy nhớ đến tương lai và không ngừng kiểm tra bản thân. Nếu bạn muốn nó được thực hiệnrun(), hãy gọi nóstart(). Tiếp tục nào.

Phương thức Thread.sleep()

Để tạm dừng việc thực thi luồng hiện tại trong một thời gian, hãy sử dụng lệnh sleep(). Đa luồng: các phương thức của lớp Thread làm gì - 3Phương thức này sleep()lấy tham số là số mili giây, tức là thời gian mà luồng cần được chuyển sang chế độ ngủ.

public class Main {

   public static void main(String[] args) throws InterruptedException {

       long start = System.currentTimeMillis();

       Thread.sleep(3000);

       System.out.println(" - Сколько я проспал? \n - " + ((System.currentTimeMillis()-start)) / 1000 + " секунды");

   }
}
Đầu ra của bàn điều khiển: - Tôi đã ngủ bao lâu? - 3 giây Xin lưu ý: phương thức này sleep()là tĩnh: nó đặt luồng hiện tại ở chế độ ngủ. Đó là, cái đang hoạt động vào lúc này. Một sắc thái quan trọng khác: dòng chảy trong trạng thái ngủ có thể bị gián đoạn. Trong trường hợp này, một ngoại lệ sẽ xảy ra trong chương trình InterruptedException. Chúng ta sẽ xem xét một ví dụ dưới đây. Nhân tiện, điều gì xảy ra sau khi chủ đề “thức dậy”? Liệu nó có ngay lập tức tiếp tục thực hiện từ nơi nó đã dừng lại không? KHÔNG. Sau khi luồng thức dậy—khi thời gian trôi qua dưới dạng đối số hết hạn Thread.sleep()—nó sẽ chuyển sang trạng thái có thể chạy được . Tuy nhiên, điều này không có nghĩa là bộ lập lịch luồng sẽ chạy nó. Rất có thể nó sẽ ưu tiên cho một số chủ đề “không ngủ” khác và chủ đề “mới được đánh thức” của chúng tôi sẽ tiếp tục hoạt động sau đó một chút. Hãy nhớ rằng: “thức dậy không có nghĩa là tiếp tục làm việc ngay lúc đó!”

Phương thức Thread.join()

Đa luồng: các phương thức của lớp Thread làm gì - 4Phương thức join()tạm dừng việc thực thi luồng hiện tại cho đến khi một luồng khác hoàn thành. Nếu chúng ta có 2 luồng t1t2, và chúng ta viết -

t1.join()
t2sẽ không bắt đầu làm việc cho đến khi t1 hoàn thành công việc của mình. Phương thức này join()có thể được sử dụng để đảm bảo trình tự thực hiện của các luồng. Hãy xem công việc join()bằng một ví dụ:

public class ThreadExample extends Thread {

   @Override
   public void run() {

       System.out.println("Начало работы потока " + getName());

       try {
           Thread.sleep(5000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
       System.out.println("Поток " + getName() +  " завершил работу.");
   }
}


public class Main {

   public static void main(String[] args) throws InterruptedException {

       ThreadExample t1 = new ThreadExample();
       ThreadExample t2 = new ThreadExample();

       t1.start();

      
 /*Второй поток t2 начнет выполнение только после того, How будет завершен
       (or бросит исключение) первый поток - t1*/
       try {
           t1.join();
       } catch (InterruptedException e) {
           e.printStackTrace();
       }

       t2.start();

       //Главный поток продолжит работу только после того, How t1 и t2 завершат работу
       try {
           t1.join();
           t2.join();
       } catch (InterruptedException e) {
           e.printStackTrace();
       }

       System.out.println("Все потоки закончor работу, программа завершена");

   }
}
Chúng tôi đã tạo ra một lớp đơn giản ThreadExample. Nhiệm vụ của nó là hiển thị thông báo trên màn hình về việc bắt đầu công việc, sau đó chìm vào giấc ngủ trong 5 giây và cuối cùng thông báo về việc hoàn thành công việc. Không có gì phức tạp. Logic chính được chứa trong lớp Main. Hãy xem nhận xét: bằng cách sử dụng phương thức này, join()chúng ta đã kiểm soát thành công trình tự thực thi của các luồng. Nếu bạn nhớ phần đầu của chủ đề thì bộ lập lịch chuỗi đã thực hiện việc này. Anh ấy tung ra chúng theo ý mình: mỗi lần một cách khác nhau. Ở đây, bằng cách sử dụng phương thức này, chúng tôi đảm bảo rằng luồng đầu tiên sẽ được khởi chạy và thực thi t1, sau đó là luồng t2và chỉ sau chúng là luồng chính của việc thực thi chương trình. Hãy tiếp tục. Trong các chương trình thực tế, bạn sẽ thường gặp phải tình huống cần tạm dừng việc thực thi một số luồng. Ví dụ: luồng của chúng tôi đang chạy nhưng nó đang chờ một sự kiện hoặc điều kiện nhất định được đáp ứng. Nếu điều này xảy ra, nó sẽ dừng lại. Có lẽ sẽ hợp lý nếu có một số phương thức như stop(). Tuy nhiên, mọi thứ không đơn giản như vậy. Ngày xửa ngày xưa, có một phương thức Thread.stop()trong Java thực sự tồn tại và cho phép bạn làm gián đoạn công việc của một luồng. Nhưng sau đó nó đã bị xóa khỏi thư viện Java. Bạn có thể tra cứu nó trong tài liệu của Oracle và thấy rằng nó được đánh dấu là không dùng nữa . Tại sao? Bởi vì nó chỉ đơn giản là dừng dòng chảy mà không cần thực hiện thêm bất kỳ công việc nào. Ví dụ: một luồng có thể làm việc với dữ liệu và thay đổi nội dung nào đó trong đó. Sau đó, anh ta đột ngột bị đánh gục stop()giữa lúc đang làm việc - và chỉ thế thôi. Không có sự tắt máy chính xác, không giải phóng tài nguyên, thậm chí không xử lý lỗi - không có điều nào trong số này xảy ra. Nói một cách phóng đại, phương pháp này stop()chỉ đơn giản là phá hủy mọi thứ trên đường đi của nó. Hoạt động của nó có thể được so sánh với cách ai đó rút phích cắm ra khỏi ổ cắm để tắt máy tính. Có, bạn có thể đạt được kết quả mong muốn. Nhưng mọi người đều hiểu rằng trong một vài tuần nữa máy tính sẽ không nói “cảm ơn” vì điều này. Vì lý do này, logic làm gián đoạn các luồng trong Java đã được thay đổi và bây giờ một phương thức đặc biệt được sử dụng - interrupt().

Phương thức Thread.interrupt()

Điều gì xảy ra nếu bạn gọi một phương thức interrupt() trên một luồng ? Có 2 lựa chọn:
  1. Ví dụ: nếu đối tượng đang ở trạng thái chờ tại thời điểm đó joinhoặc sleep, thì quá trình chờ đợi sẽ bị gián đoạn và chương trình sẽ ném InterruptedException.
  2. Nếu luồng ở trạng thái hoạt động tại thời điểm đó, cờ boolean của đối tượng sẽ được đặt interrupted.
Nhưng chúng ta sẽ phải kiểm tra đối tượng để tìm giá trị của cờ này và tự mình hoàn thành công việc một cách chính xác! Với mục đích này, lớp Threadcó một phương thức đặc biệt - boolean isInterrupted(). Hãy quay lại ví dụ về đồng hồ trong bài giảng chính của khóa học. Để thuận tiện, nó được đơn giản hóa một chút:

public class Clock extends Thread {

   public static void main(String[] args) throws InterruptedException {
       Clock clock = new Clock();
       clock.start();

       Thread.sleep(10000);
       clock.interrupt();
   }

   public void run() {
       Thread current = Thread.currentThread();

       while (!current.isInterrupted())
       {
           try {
               Thread.sleep(1000);
           } catch (InterruptedException e) {
               System.out.println("Работа потока была прервана");
               break;
           }
           System.out.println("Tik");
       }
   }
}
Trong trường hợp của chúng tôi, đồng hồ bắt đầu tích tắc từng giây. Vào giây thứ 10, chúng ta làm gián đoạn dòng chảy của đồng hồ. Như bạn đã biết, nếu luồng mà chúng ta đang cố gắng làm gián đoạn đang ở một trong các trạng thái chờ, điều này sẽ dẫn đến InterruptedException. Loại ngoại lệ này là ngoại lệ được kiểm tra, vì vậy nó có thể dễ dàng bị phát hiện và logic kết thúc chương trình của chúng tôi được thực thi. Đó là những gì chúng tôi đã làm. Đây là kết quả của chúng ta: Tik Tik Tik Tik Tik Tik Tik Tik Tik Công việc của thread đã bị gián đoạn, đến đây là phần giới thiệu của chúng ta về các phương thức chính của lớp Thread. Để củng cố kiến ​​thức, bạn có thể xem video bài giảng về đa luồng này:
nó sẽ phục vụ như một tài liệu bổ sung tuyệt vời! Cuối cùng, sau phần tổng quan về các phương pháp, nó sẽ cho biết chính xác những gì chúng ta sẽ trải qua tiếp theo trong khóa học :) Chúc may mắn!
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION