CFSDN nhấn mạnh vào giá trị tạo ra nguồn mở và chúng tôi cam kết xây dựng nền tảng chia sẻ tài nguyên để mọi nhân viên CNTT có thể tìm thấy thế giới tuyệt vời của bạn tại đây.
Bài viết trên blog CFSDN về giao tiếp luồng Java và tóm tắt kiến thức đánh thức sai luồng này được tác giả sưu tầm và biên soạn. Nếu các bạn quan tâm đến bài viết này thì nhớ like nhé.
Giao tiếp chủ đề
Khi các luồng chạy nội bộ, việc lập lịch trình của luồng có một mức độ minh bạch nhất định và chương trình thường không thể kiểm soát việc thực thi xoay vòng của các luồng. Nhưng bản thân Java cung cấp một số cơ chế để đảm bảo rằng các luồng chạy phối hợp.
Giả sử rằng hiện có hai luồng trong hệ thống, đại diện cho việc gửi và rút tiền. Khi tiền được gửi, nó sẽ được rút ngay lập tức và chuyển vào tài khoản được chỉ định. Điều này liên quan đến sự cộng tác giữa các luồng, sử dụng ba phương thức wait(), notification() và notificationAll() do lớp Object cung cấp. Chúng không thuộc về lớp Thread mà thuộc về Object và ba phương thức này phải được xử lý bởi lớp Object. đối tượng giám sát. Gọi:
- Phương thức sửa đổi được đồng bộ hóa, vì phiên bản mặc định của lớp này (đây) là trình giám sát đồng bộ hóa, nên nó có thể được gọi trực tiếp trong phương thức đồng bộ hóa
- Khối mã đồng bộ hóa được sửa đổi bởi trình giám sát đồng bộ hóa là đối tượng trong dấu ngoặc được đồng bộ hóa, do đó nó phải được gọi bằng cách sử dụng đối tượng này.
Ba phương pháp được giải thích dưới đây:
- wait(): Luồng hiện tại chờ, giải phóng khóa đối tượng hiện tại và từ bỏ CPU cho đến khi các luồng khác sử dụng thông báo hoặc thông báo Tất cả để đánh thức luồng.
- thông báo (): Đánh thức một luồng duy nhất đang chờ trên màn hình đồng bộ hóa này. Nếu có nhiều luồng, hãy đánh thức một luồng ngẫu nhiên. Việc thực thi thông báo sẽ không giải phóng khóa ngay lập tức. Chỉ các luồng ở trạng thái chờ mới có thể tranh giành khóa đối tượng sau khi thoát hoàn toàn khối mã được đồng bộ hóa hoặc gặp phải tình trạng chờ giữa chừng.
- notificationAll(): Đánh thức tất cả các luồng trên màn hình đồng bộ hóa này, giống như trên.
Bây giờ hai phương thức đồng bộ hóa được sử dụng để thể hiện việc gửi và rút tiền.
- Khi số dư bằng 0, hãy nhập quy trình gửi tiền. Sau khi thực hiện thao tác gửi tiền, hãy đánh thức chuỗi rút tiền.
- Khi số dư bằng 0 thì vào quá trình rút tiền, tìm num==0, vào trạng thái block, chờ được đánh thức
- /**
- * Tiết kiệm một đô la
- *
- * @throws Ngoại lệ bị gián đoạn
- */
- công cộng đồng bộ vô hiệu tăng() ném Ngoại lệ bị ngắt {
- // Khi số dư bằng 1 nghĩa là tiền đã được gửi và đang chờ rút. Phương thức gửi tiền bị chặn
- nếu như (trong một == 1) {
- cái này.Chờ đợi();
- }
- //Thực hiện thao tác gửi tiền
- trong một++;
- Hệ thống.ngoài.inl(Chủ đề.hiện tạiThread().lấy Tên() + ":số=" + trong một);
- // Đánh thức các chủ đề khác
- cái này.thông báoTất cả();
- }
-
- /**
- * Rút một đô la
- *
- * @throws Ngoại lệ bị gián đoạn
- */
- công cộng đồng bộ vô hiệu giảm bớt() ném Ngoại lệ bị ngắt {
- // Khi số dư bằng 0 nghĩa là tiền đã được rút và đang chờ gửi. Phương thức rút tiền bị chặn
- nếu như (trong một == 0) {
- cái này.Chờ đợi();
- }
- trong một--;
- Hệ thống.ngoài.inl(Chủ đề.hiện tạiThread().lấy Tên() + ":số=" + trong một);
- cái này.thông báoTất cả();
- }
Phương thức gọi:
- riêng tư số nguyên trong một = 0;
-
- công cộng tĩnh vô hiệu chủ yếu(Sợi dây[] các đối số) {
- Bài kiểm tra Bài kiểm tra = mới Bài kiểm tra();
-
- mới Chủ đề(() -> {
- vì (số nguyên Tôi = 0; Tôi < 10; Tôi++) {
- thử {
- Bài kiểm tra.tăng();
- } nắm lấy (Ngoại lệ bị ngắt Và) {
- Và.inStackTrace();
- }
- }
- }, "Tiết kiệm tiền").bắt đầu();
-
- mới Chủ đề(() -> {
- vì (số nguyên Tôi = 0; Tôi < 10; Tôi++) {
- thử {
- Bài kiểm tra.giảm bớt();
- } nắm lấy (Ngoại lệ bị ngắt Và) {
- Và.inStackTrace();
- }
- }
- }, "Rút tiền").bắt đầu();
- }
Không có gì sai với kết quả.

Chủ đề đánh thức sai
Có vẻ như không có vấn đề gì với giao tiếp chủ đề trên, nhưng nếu số người gửi tiền và số người rút tiền tăng lên 1 vào thời điểm này, hãy xem kết quả đang chạy.
- riêng tư số nguyên trong một = 0;
-
- công cộng tĩnh vô hiệu chủ yếu(Sợi dây[] các đối số) {
- Bài kiểm tra Bài kiểm tra = mới Bài kiểm tra();
-
- mới Chủ đề(() -> {
- vì (số nguyên Tôi = 0; Tôi < 10; Tôi++) {
- thử {
- Bài kiểm tra.tăng();
- } nắm lấy (Ngoại lệ bị ngắt Và) {
- Và.inStackTrace();
- }
- }
- }, "Tiết kiệm tiền 1").bắt đầu();
-
- mới Chủ đề(() -> {
- vì (số nguyên Tôi = 0; Tôi < 10; Tôi++) {
- thử {
- Bài kiểm tra.giảm bớt();
- } nắm lấy (Ngoại lệ bị ngắt Và) {
- Và.inStackTrace();
- }
- }
- }, "Rút tiền 1").bắt đầu();
-
- mới Chủ đề(() -> {
- vì (số nguyên Tôi = 0; Tôi < 10; Tôi++) {
- thử {
- Bài kiểm tra.tăng();
- } nắm lấy (Ngoại lệ bị ngắt Và) {
- Và.inStackTrace();
- }
- }
- }, "Tiết kiệm tiền 2").bắt đầu();
-
- mới Chủ đề(() -> {
- vì (số nguyên Tôi = 0; Tôi < 10; Tôi++) {
- thử {
- Bài kiểm tra.giảm bớt();
- } nắm lấy (Ngoại lệ bị ngắt Và) {
- Và.inStackTrace();
- }
- }
- }, "Rút tiền 2").bắt đầu();
- }
Kết quả tạo ra không còn là ban đầu chỉ có 0 và 1.

Lý do cho kết quả này là do đánh thức sai giữa các luồng.
Vì hiện tại có nhiều chủ đề rút tiền và gửi tiền tương ứng. Giả sử rằng một trong các luồng gửi tiền hoàn tất việc thực thi và sử dụng chờ để giải phóng khóa giám sát đồng bộ hóa, các luồng rút tiền còn lại sẽ được đánh thức cùng lúc, số dư là 1. Nếu 10 rút tiền cùng lúc, số dư sẽ là 1. số dư sẽ trở thành -9 gây ra kết quả sai.
Do đó, mỗi khi một thread được đánh thức từ trạng thái chờ, nó phải được kiểm tra lại để xem liệu nó có đáp ứng các điều kiện đánh thức hay không. Nếu không, nó sẽ tiếp tục chờ.
Vì nhiều luồng được đánh thức cùng một lúc nên phán đoán if tại if(xxxx){wait();} sẽ chỉ được thực thi một lần. Khi luồng được đánh thức tiếp theo xuất hiện, vì if đã được đánh giá nên nó sẽ tiếp tục trực tiếp. từ câu lệnh sau khi chờ thực thi, do đó, việc thay đổi if thành while có thể giải quyết vấn đề này. Lần tiếp theo luồng được đánh thức xuất hiện, while sẽ đánh giá lại và phát hiện ra rằng luồng được đánh thức cuối cùng đã lấy được khóa, vì vậy luồng được đánh thức sai này sẽ xảy ra. tiếp tục chờ khóa.
- /**
- * Tiết kiệm một đô la
- *
- * @throws Ngoại lệ bị gián đoạn
- */
- công cộng đồng bộ vô hiệu tăng() ném Ngoại lệ bị ngắt {
- trong khi (trong một == 1) {// Để ngăn mỗi luồng đánh thức đến chỉ đánh giá một lần và gây ra đánh thức sai, hãy thay thế nó bằng while
- cái này.Chờ đợi();
- }
- trong một++;
- Hệ thống.ngoài.inl(Chủ đề.hiện tạiThread().lấy Tên() + ":số=" + trong một);
- cái này.thông báoTất cả();
- }
-
- /**
- * Rút một đô la
- *
- * @throws Ngoại lệ bị gián đoạn
- */
- công cộng đồng bộ vô hiệu giảm bớt() ném Ngoại lệ bị ngắt {
- trong khi (trong một == 0) {
- cái này.Chờ đợi();
- }
- trong một--;
- Hệ thống.ngoài.inl(Chủ đề.hiện tạiThread().lấy Tên() + ":số=" + trong một);
- cái này.thông báoTất cả();
- }
Chạy lại và kết quả là bình thường:

Phần này kết thúc bài viết này về bản tóm tắt kiến thức về giao tiếp luồng Java và đánh thức sai luồng. Để biết thêm thông tin về giao tiếp luồng Java và đánh thức sai luồng, vui lòng tìm kiếm các bài viết trước của tôi hoặc tiếp tục duyệt qua các bài viết liên quan sau đây. sẽ đọc thêm trong tương lai. Ủng hộ tôi! .
Liên kết gốc: https://blog.csdn.net/qq_26012495/article/details/117908249.
Cuối cùng, bài viết này về giao tiếp luồng Java và tóm tắt kiến thức đánh thức sai luồng ở đây. Nếu bạn muốn biết thêm về giao tiếp luồng Java và tóm tắt kiến thức đánh thức sai luồng, vui lòng tìm kiếm các bài viết CFSDN hoặc tiếp tục duyệt qua các bài viết liên quan. Tôi hy vọng tất cả các bạn sẽ ủng hộ blog của tôi trong tương lai! .
Tôi là một lập trình viên xuất sắc, rất giỏi!