TS LÝ ANH TUẤN TS LÊ NGUYỄN TUẤN THÀNH BÀI GIẢNG LẬP TRÌNH JAVA NHÃ XUẤT BẢN BÁCH KHOA HÀ NỘI Biên mục trên xuất bản phẩm của Thư viện Quốc gia Việt Nam Lý Anh Tuấn Bài giảng lập trình Java / Lý Anh T[.]
TS LÝ ANH TUẤN - TS LÊ NGUYỄN TUẤN THÀNH BÀI GIẢNG LẬP TRÌNH JAVA NHÃ XUẤT BẢN BÁCH KHOA HÀ NỘI Biên mục xuất phẩm Thư viện Quốc gia Việt Nam Lý Anh Tuấn Bài giảng lập trình Java / Lý Anh Tuấn, Lê Nguyễn Tuấn Thành - H : Bách khoa Hà Nội, 2019 - 408tr : hình vẽ, bảng ; 27cm Thư mục: tr 407 Ngơn ngữ lập trình Ngơn ngữ Java Bài giảng 005.133 - dc23 BKM0106p-CIP LỜI NÓI ĐÀU Vào cuối năm 1995, ngơn ngữ lập trình Java bùng nổ Internet trở nên tiếng Lời hứa cơng nghệ Java trờ thành chất kết dính phổ biến kết nối người dùng với thông tin đến từ nơi từ máy chủ web, sở liệu, nhà cung cấp thông tin nguồn khác Thật vậy, Java vị trí độc tôn đế thực lời hứa Java ngôn ngữ thiết kế vững tất nhà cung cấp lớn chấp nhận, ngoại trừ Microsoft Các tính bảo mật an tồn có sẵn đem đến yên tâm cho người lập trình lẫn người dùng chương trình Java Java chí cịn có hỗ trợ tích họp tác vụ lập trình nâng cao, chang hạn lập trình mạng, kết nối sở liệu đa luồng Kể từ năm 1995, mười bốn phiên Bộ công cụ phát triển Java (Java Development Kit) phát hành Trong suốt 24 năm qua, giao diện lập trình ứng dụng (API) phát triến từ khoảng 200 lên đến 4.000 lớp API mở rộng nhiều lĩnh vực xây dựng giao diện người dùng, quản lý sờ liệu, quốc tế hóa, bảo mật xử lý XML Ở Việt Nam, ngơn ngữ lập trình, cơng nghệ Java đưa vào giảng dạy số trường đại học sở đào tạo lập trình viên chuyên nghiệp Sau thời gian tìm hiếu, làm việc tham gia giảng dạy lập trình Java, nhóm tác giả định biên soạn “Bài giăng Lập trình Java” nhằm phục vụ công tác giảng dạy học tập sinh viên chuyên ngành công nghệ thông tin Nội dung giảng tập trung vào kiến thức lập trình Java, giúp người đọc bước đầu tiếp cập dễ dàng với công nghệ này, bước đệm giúp trở thành lập trình viên Java chuyên nghiệp Ngoài ra, giảng bao gồm số chủ đề nâng cao lập trình sở liệu, lập trình mạng, lập trình đồng thời Đe có thê đọc hiếu giảng này, người đọc cần nắm vững kiến thức về: nhập mơn lập trình, lập trình hướng đối tượng Đây lần xuất giảng nên dù nhóm tác giả cố gắng, chắn không tránh khỏi thiếu sót định Nhóm tác giả mong nhận ý kiến đóng góp thầy cô, đồng nghiệp bạn đọc để tiếp tục hồn thiện giảng nhằm phục vụ tốt cho việc học tập sinh viên Cấu trúc giảng bao gồm: Chương - Các khái niệm Chương mở đầu giới thiệu chung Java Bạn tìm thấy chương khái niệm đặc trưng Java Các đặc điểm, cách cài đặt cách biên dịch thông dịch Java nói Chương giới thiệu thành phần sở ngôn ngữ Java với khái niệm cấu trúc chương trình, biến, hằng, kiểu liệu, toán tử cách xuất nhập liệu đế từ xây dựng cho ứng dụng dựa Java Chương - Điều khiến luồng xử lý ngoại lệ Giống hầu hết ngơn ngữ lập trình, Java quản lý điều khiển luồng với câu lệnh rẽ nhánh lặp Các câu lệnh rẽ nhánh lặp Java tương tự câu lệnh rẽ nhánh lặp ngôn ngữ khác Chúng giống với câu lệnh tương ứng ngôn ngữ c C++ Quản lý ngoại lệ cách để quản lý điều khiển luồng Bạn sử dụng tiện ích xử lý ngoại lệ Java để thêm vào mã lệnh cho trường họp bất thường sau viết xong chương trình để xử lý tình lỗi thực thi chương trình Chương - Lập trình hướng đoi tượng Chương trình bày kỹ thuật lập trình hướng đối tượng dựa ngơn ngữ lập trình Java: Khai báo lóp, thuộc tính, phương thức lóp; kỹ thuật kế thừa, lớp trừu tượng, cài đặt nạp chồng đa hình Java Cách khai báo sử dụng giao diện, lóp gói trình bày chương Nội dung nhấn mạnh kỹ thuật tri đặc điểm quan trọng lập trình hướng đối tượng tính đóng gói, tính kế thừa, tính đa hình, với ví dụ minh họa cụ cuối chương Chương - Mảng, xâu ký tự tập hợp Chương trình bày khái niệm kỹ thuật liên quan đến việc xử lý mảng, xâu ký tự tập hợp Java Đây cấu trúc liệu Java sử dụng để tạo đối tượng tập đối tượng Java hỗ trợ giao diện, lớp giúp quản lý vào thao tác với kiểu đối tượng Trong phần mảng, trước hết giải thích cách khai báo tên tham chiếu đến mảng, cách tạo mảng cách tạo liên kết giá trị mục thành viên mảng Sau đó, chúng tơi trình bày thơng qua ví dụ loạt kỹ thuật biến để xử lý thông tin lưu mảng Như với hầu hết ngơn ngữ lập trình, xâu ký tự sử dụng rộng rãi Java, đó, API Java có nhiều chức để giúp bạn thao tác xâu ký tự Các lóp giúp xử lý xâu bao gồm java.lang.String, java.lang.StringBuffer, java.util.StringTokenizer mơ tả chương Java cịn cung cấp số lớp tiện ích giúp bạn quản lý tập hợp đối tượng (Collection) Các lóp tập hợp cho phép bạn làm việc với đối tượng mà khơng cần quan tâm đến kiểu chúng, chúng hữu ích để quản lý đối tượng mức độ trừu tượng cao Chương mơ tả các giao diện, lóp tập hợp cấu trúc phân cap Collection Java Chương - Thao tác với tệp Trong chưong tìm hiếu luồng (stream) cách dùng luồng đế xử lý tập tin liệu Luồng khái niệm không Java đưa vào sử dụng gắn liền với thân ngơn ngữ, thực thao tác xuất nhập cách trừu tượng hóa mức liệu Luồng sử dụng nhiều chưong trình ứng dụng Java chưong trình truy xuất mạng tập tin đĩa Hiểu luồng cách hoạt động luồng giúp ta tiến sâu vào giới Java Chương - Lập trình giao diện đồ họa Chương giới thiệu cách viết chương trình Java sử dụng giao diện đồ họa người dùng (GUI - Graphical User Interface) Trước hết, chúng tơi trình bày cách viết chương trình cho phép thiết lập kích cỡ vị trí cửa số hình, hiến thị văn với nhiều font chữ cửa sổ, hiển thị hình ảnh, Sau chúng tơi trình bày cách để xử lý kiện keystrokes nhấp chuột, cách để thêm thành phần giao diện menu, nút bam (button) vào ứng dụng Khi bạn đọc xong chương này, bạn nắm thành phần cốt yếu để viết ứng dụng đồ họa Chương - Kết nối xử lý sở liệu Java JDBC Java API để kết nối thực thi truy vấn với sờ liệu JDBC API sử dụng trình điều khiển JDBC (JDBC Driver) để kết nối với sở liệu JDBC làm việc với Java nhiều tảng đa dạng Windows, Mac OS, Unix, Chương giới thiệu Java JDBC cung cấp đầy đủ khái niệm kiến thức Java JDBC cho lập trình viên Java mong muốn tìm hiểu ve JDBC Framework cách sử dụng Chương — Lập trình mạng Với chương bạn làm quen tìm hiểu cách lập trình mạng ngơn ngữ Java Java cung cấp lóp Socket, ServerSocket, DatagramSocket, đủ mạnh để thiết kế ứng dụng theo mơ hình khách/chủ (client/server) Kết thúc chương bạn tự xây dựng ứng dụng thông dụng trao đối liệu, truy cập máy chủ từ xa, cách đọc xử lý trang Web mạng Internet Chương - Lập trình đồng thời Các ứng dụng chạy đa luồng đem lại nhiều lợi ích, giúp tận dụng CPU đa nhân đế phân công cho mồi nhân luồng xử lý nhằm tăng tốc độ tính tốn tốn Hay tại, số ứng dụng sử dụng GPU (Bộ xử lý đồ họa) đế tính tốn hiệu cao dựa vào số nhân vô lớn GPU Chương trình bày cách thêm khả đa luồng vào ứng dụng Java Các tác giả MỤC LỤC LỜI NÓI ĐÀU Chương CÁC KHÁI NIỆM co BẢN 15 1.1 Giới thiệu ngôn ngũ’ Java 15 1.1.1 Java 15 1.1.2 Các đặc trưng Java 16 1.1.3 Các kiểu ứng dụng Java 18 1.1.4 Máy ảo Java (JVM - Java Virtual Machine) 19 1.2 Mơi trường lập trình Java 20 1.2.1 Cài đặt JDK 21 1.2.2 cấu trúc thư mục JDK 22 1.2.3 Kiểm tra cài đặt JDK 24 1.2.4 Cài đặt JDK9 24 1.2.5 Thiết lập biến môi trường .26 1.2.6 Biên dịch thực thi Java bang Command Prompt 28 1.2.7 Giới thiệu công cụ JSell 29 1.2.8 Cài đặt công cụ phát triển 29 1.3 Các thành phần sở Java 36 1.3.1 Kiến trúc chương trình Java 36 1.3.2 Chương trình Java 39 1.3.3 Kiểu liệu 41 1.3.4 Biến 43 1.3.5 Các toán tử 45 1.3.6 Các hàm toán học 50 1.3.7 Xuất nhập liệu console 53 Bài tập 57 Chương ĐIỀU KHIÉN LUỒNG VÀ xử LÝ NGOẠI LỆ 59 2.1 Các cấu trúc rẽ nhánh 59 2.1.1 Lệnh if-else 59 2.1.2 Lệnh switch 61 2.2 Các cấu trúc lặp 63 2.2.1 Vòng lặp while 63 2.2.2 Vòng lập do-while 65 2.2.3 Vòng lặp for 66 2.2.4 Các lệnh break continue 68 2.3 Xử lý ngoại lệ 71 2.3.1 Mục đích việc xử lý ngoại lệ 71 2.3.2 Mơ hình xử lý ngoại lệ 71 2.3.3 Đặc tả ngoại lệ 72 2.3.4 Ném ngoại lệ 72 2.3.5 Bắt ngoại lệ 73 2.3.6 Khối finally 76 2.3.7 Một số lóp ngoại lệ chuẩn Java 78 Bài tập 79 Chương LẬP TRÌNH HƯỚNG ĐỔI TƯỢNG 81 3.1 Lóp 81 3.1.1 Khai báo/định nghĩa lóp 81 3.1.2 Sử dụng lóp 82 3.1.3 Khai báo thuộc tính lớp 82 3.1.4 Khai báo sử dụng phương thức lớp 83 3.1.5 Phương thức khời tạo lớp 85 3.1.6 Biến this 87 3.1.7 Khai báo chồng phương thức 87 3.1.8 Các thành phần tĩnh 88 3.1.9 Phương thức fínalize() 90 3.2 Đặc điểm hướng đối tượng Java 91 3.2.1 Sự kế thừa 92 3.2.2 Lóp trừu tượng 95 3.2.3 Đa hình 99 3.3 Giao diện, lóp trong, gói 102 3.3.1 Giao diện (interface) 102 3.3.2 Lóp 105 3.3.3 Gói 107 3.4 Ví dụ minh họa 112 3.4.1 Ví dụ 112 3.4.2 Ví dụ 119 Bài tập 122 Chương MẢNG, XÂU KỶ Tự VÀ TẬP HỢP 125 4.1 Măng 125 4.1.1 Mảng chiều 125 4.1.2 Mảng hai chiều 133 4.2 Xâu ký tự 139 4.2.1 Lớp String 139 4.2.2 Lớp StringBuffer 142 4.2.3 Lớp StringTokenizer 146 4.3 Một số lóp Java 149 4.3.1 Lớp Object 149 4.3.2 Các lóp Wrapper 150 4.4 Các lóp tập họp 157 4.4.1 Collection 159 4.4.2 Set (tập họp) 160 4.4.3 List (danh sách) 162 4.4.4 Map (ánh xạ) 164 4.4.5 SortedSet SortedMap 166 4.4.6 Lóp TreeSet TreeMap 167 Bài tập 168 Chương THAO TÁC VỚI FILE 170 5.1 Luồng (Streams) 170 5.1.1 Khái niệm luồng 170 5.1.2 Luồng byte (Byte Streams) 171 5.1.3 Luồng ký tự (Character Streams) 172 5.1.4 Những luồng định nghĩa trước (The Predefined Streams) 174 5.2 Sử dụng luồng byte 174 5.2.1 Đọc liệu từ Console 175 5.2.2 Xuất liệu Console 176 5.2.3 Đọc ghi file dùng luồng Byte 176 5.2.4 Đọc ghi liệu nhị phân 180 5.3 File truy cập ngẫu nhiên (Random Access File) 183 5.4 Sử dụng luồng ký tự 185 5.4.1 Nhập Console dùng luồng ký tự 186 5.4.2 Xuất Console dùng luồng ký tự 188 5.4.3 Đọc/ghi file dùng luồng ký tự 189 5.5 Lớp File 191 Bài tập 194 Chương LẬP TRÌNH GIAO DIỆN ĐỒ HỌA 195 6.1 Giới thiệu Swing 195 6.2 Tạo khung (Frame) 199 6.3 Định vị khung 202 6.3.1 Các thuộc tính khung 204 6.3.2 Xác định kích thước khung hình tốt 204 6.4 Hiển thị thông tin thành phần 207 6.5 Xử lý kiện 212 6.5.1 Khái niệm xử lý kiện 212 6.5.2 Ví dụ: Xử lý nút bấm 215 6.5.3 Các lớp Adapter 220 6.5.4 Các kiện chuột 224 6.5.5 Hệ thống phân cấp kiện AWT 233 10 dadd dastore Những đoạn mã bytecode có ý nghĩa khơng quan trọng Mấu chốt câu lệnh tăng tạo nhiều lệnh luồng thực thi lệnh bị ngắt lệnh Khả việc hư hỏng xảy bao nhiêu? Chúng ta tăng khả quan sát vấn đề cách xen kẽ câu lệnh in hình với câu lệnh cập nhật tài khoản Neu bạn bó qua câu lệnh in hình, rùi ro việc hư hỏng thấp chút mồi lưồng làm việc trước ngủ lần trông không giống lập lịch ngăn cản (preempt) chừng q trình tính tốn Tuy nhiên, rủi ro việc hư hỏng không bị loại bỏ hoàn toàn Neu bạn chạy nhiều luồng máy tính có tải nặng, chương trình thất bại, chí bạn loại bỏ câu lệnh in hình Sự thất bại xảy sau vài phút, vài hay vài ngày Vấn đề thực tế trình thực phương thức transfer bị ngắt chừng Neu muốn đảm bảo phương thức thực thi toàn trước luồng quyền kiểm soát, trạng thái đối tượng tài khoản ngân hàng không hư hỏng 9.5.3 Đối tượng khóa (Lock Objects) Có hai chế đế bảo vệ khối mã lệnh khỏi việc truy cập đồng thời Ngơn ngữ Java cung cấp từ khóa synchronized cho mục đích Java SE 5.0 giới thiệu lóp ReentrantLock Từ khóa synchronized tự động cung cấp khóa “điều kiện' (condition) kèm Điều khiến trờ nên mạnh mẽ thích họp cho hầu hết trường họp yêu cầu khóa tường minh Tuy nhiên, tin dễ dàng hiểu từ khóa synchronized sau bạn hiểu khóa (lock) điều kiện (condition) cách độc lập Gói java.util.concurrent cung cấp lóp riêng biệt cho chế tảng Một bạn hiếu chế này, giới thiệu từ khóa synchronized Phác thảo để bảo vệ khối mã với ReentrantLock là: myLock.lockQ; // Một đối tượng ReentrantLock try { 394 } finally { myLock-unlockQ; // Đảm bảo lock khóa lại ngoại lệ ném } cấu trúc đảm bảo có luồng thời điếm vào khu vực quan trọng Ngay luồng khóa đối tượng lock, khơng có luồng khác qua câu lệnh myLock.lock() Khi luồng khác gọi phương thức lock, chúng bị vơ hiệu hóa luồng mở khóa cho đối tượng lock LƯU Ý: Một điều tối quan trọng thao tác unlock phải để mệnh đề finally Neu đoạn mã khu vực quan trọng ném ngoại lệ, lock phải mờ khóa Neu khơng, luồng khác bị khóa vĩnh viễn CHÚ Ý: Khi bạn sử dụng khóa, bạn khơng thể sử dụng mệnh đề try-yvỉth-resources Đầu tiên, phương thức unlock không gọi close Nhưng đổi tên, mệnh đề try-with-resources khơng hoạt động Tiêu đề mong muốn khai báo biến Nhưng bạn sử dụng khóa, bạn muốn dùng lại biến chia sẻ luồng Bây giờ, sử dụng khóa để bảo vệ phương thức transfer lóp Bank public class Bank { private Lock bankLock = new ReentrantLockQ; // ReentrantLock cài đặt giao diện Lock public void transferfint from, int to, int amount){ bankLock.lockQ; try{ System.out.print(Thread.currentThreadO); accounts [from] -= amount; System.out.printff' %10.2f from %d to %d”, amount, from, to); accounts [to] += amount; 395 System.out.printff' Total Balance: %10.2f%n", getTotalBalanceQ); } finally { bankLock.unlockQ; } } } Giả sử luồng gọi phương thức transfer bị buộc dừng (preempt) trước thực xong Giả sử luồng thứ hai gọi phương thức transfer Luồng thứ hai lấy khóa (lock) bị khóa/chặn lời gọi tới phương thức lock Nó bị vơ hiệu hóa phải đợi luồng thức hoàn thành xong phương thức transfer Khi luồng thứ mở khóa lock, luồng thứ hai tiến hành (xem hình 9.5) Hãy thử điều Thêm đoạn mã khóa vào phương thức transfer chạy lại chương trình Bạn chạy chương trình mãi mà giá trị tống lượng tiền ngân hàng không bị sai lệch Chú ý rằng, đối tượng Bank có đối tượng ReentrantLock Neu hai luồng cố gắng truy cập đối tượng Bank, khóa phục vụ để hóa (serialize) quyền truy cập Tuy nhiên, hai luồng truy cập hai đối tượng Bank khác nhau, luồng yêu cầu khóa khác khơng luồng bị chặn/khóa Đeu có thể, luồng khơng can thiệp luồng khác chúng thao tác thể Bank khác Khóa gọi reentrant bời luồng lặp lại yêu cầu khóa mà sờ hữu Khóa có biến đếm hold count để lưu vết lời gọi lồng tới phương thức lock Tiến trình phải gọi unlock cho lần gọi lock để từ bỏ/nhả (relinquish) khóa Do tính này, đoạn mã bảo vệ bời khóa gọi phương thức khác sử dụng khóa giống Ví dụ, phương thức transfer gọi phương thức getTotalBalance, mà khóa đối tượng bankLock khiến đối tượng có giá trị hold count Khi thoát khỏi phương thức getTotalBalance, giá trị hold count quay ngược ve Khi thoát khỏi phương thức transfer, giá trị hold count quay ve luồng nhả khóa 396 Hình 9.5 So sánh luồng đồng khơng đồng Nhìn chung, bạn muốn bảo vệ khối lệnh cập nhật điều tra (inspect) đối tuợng chia sẻ, để bạn đảm bảo thao tác hoàn thành việc chạy trước luồng khác sử dụng đối tượng CHÚ Ý: Hãy cẩn thận đảm bảo đoạn mã khu vực quan trọng không bị vượt qua việc ném ngoại lệ Neu ngoại lệ ném trước kết thúc khu vực quan trọng, mệnh đề finally nhả khóa, đối tượng trạng thái bị hư hại CHÚ Ý: Tính cơng nghe tốt, khóa cơng chậm hon nhiều so với khóa thơng thường Bạn nên bật khóa công bạn thực biết việc bạn làm có lý đặc biệt để xem xét chất cơng chương trình Thậm chí, bạn sử dụng khóa cơng bằng, bạn khơng có đảm bảo trình lập lịch luồng cơng bang Neu trình lập lịch luồng chọn bỏ qua luồng đợi khóa thời gian dài, luồng khơng có hội để đối xử cơng khóa 397 9.5.4 Các đối tượng điều kiện (Condition Objects) Thông thường, luồng vào khu vực quan trọng khám phá khơng thể tiến hành điều kiện thỏa mãn Sử dụng đối tượng điều kiện (condition object) đế quản lý luồng u cầu khóa khơng thể thực cơng việc hữu ích Trong phần này, chúng tơi giới thiệu cài đật đối tượng điều kiện thư viện Java (Do nguyên nhân lịch sử, đối tượng điều kiện thường gọi biến điều kiện - condition variables) Chúng ta “làm mịn” chưong trình mơ phịng ngân hàng Chúng ta không muốn chuyến tiền khỏi tài khoản mà khơng có quỹ de cover việc chuyến khoản Chú ý, sử dụng mã giống như: if (bank.getBalance(from) >= amount) bank.transfer(from, to, amount); Hồn tồn luồng bị vơ hiệu hóa việc kiểm tra điều kiện thành công lời gọi phương thức transfer: if (bank.getBalance(from) >= amount) // Luồng bị vơ hiệu hóa thời điểm này! bank.transfer(from, to, amount); Tại thời điểm luồng chạy lại, lượng tiền tài khoản ngân hàng xuống lượng bạn muốn rút Bạn phải đảm bảo khơng có luồng khác thay đối lượng tiền thời điểm kiểm tra điều kiện hành động chuyển khoản Bạn làm điều cách bảo vệ việc kiếm tra điều kiện hành động chuyến khoản với khóa: public void transferfint from, int to, int amount) { bankLock.lock(); try{ while (accounts [from] < amount) { // Chờ (wait) } // Chuyển khoản (transfer funds) } finally { 398 bankLock.unlockQ; } Bây giờ, làm khơng có đủ lượng tiền tài khoản? Chúng ta đợi vài luồng khác thêm tiền vào tài khoản Nhưng luồng vừa giành quyền truy cập độc quyền tới bankLock, vậy, khơng luồng khác có hội để gửi tiền Đây lúc đối tượng điều kiện sử dụng Một đối tượng khóa có nhiều đối tượng điều kiện kèm Bạn lấy đối tượng điều kiện với phương thức newCondition Bạn cung cấp cho đối tượng điều kiện tên gọi, giúp gợi lên điều kiện mà đại diện Ví dụ, cách thiết lập đối tượng điều kiện để biểu diễn điều kiện “đủ tiềrì\ class Bank { private Condition sufficientFunds; public BankQ { sufficientFunds = bankLock.newConditionO; } } Neu phương thức transfer thấy rằng, lượng tiền đủ khơng có sẵn, gọi: sufficientFunds awaỉt(); Luồng bị vơ hiệu hóa phải từ bỏ khóa Điều khiến cho luồng khác có thể, hy vọng, tăng số dư tài khoản Có khác biệt mấu chốt luồng đợi đế yêu cầu khóa luồng vừa gọi phương thức await Khi luồng gọi phương thức await, vào tập luồng đợi (wait set) cho điều kiện Luồng khơng thực chạy (runnable) khóa sẵn sàng Thay vào đó, bị vơ hiệu hóa luồng khác gọi phương thức signalAll điều kiện Khi luồng khác chuyển tiền, nên gọi phương thức: sufficientFunds.sỉgnalAll(); Lời gọi kích hoạt lại tất luồng đợi điều kiện Khi luồng xóa bỏ khỏi tập đợi, chúng lại chạy (runnable) trình lập lịch cuối kích hoạt lại chúng Tại thời điểm đó, chúng cố gắng vào đối tượng Ngay khóa sẵn sàng, số chúng lấy khóa tiếp tục chạy vị trí dừng trước, trả từ lời gọi đến phương thức await 399 Tại thời điếm đó, luồng nên kiếm tra điều kiện lần Khơng có đảm bảo điều kiện hoàn thành - phuong thức signallAll đơn báo hiệu cho luồng chờ điều kiện có thê đuợc hồn thành thời điếm nên đuợc kiểm tra điều kiện lần LƯU Ý: Thông thường lời gọi tới phương thức await nên vòng lặp, giống mẫu sau: while(!(ok to proceed)) condition.awaitf); Điều quan trọng vài luồng khác cuối gọi phương thức signallAll Khi luồng gọi await, khơng có cách để tự kích hoạt lại Nó đặt niềm tin vào luồng khác Neu khơng có luồng khác kích hoạt lại luồng chờ, luồng chờ không chạy lại lần Điều dẫn đến tình khó chịu, gọi bế tắc (deadlock) Nếu tất luồng khác bị chặn luồng hoạt động cuối gọi phương thức OMYZZZ mà không bỏ chặn luồng khác, bị chận Khơng cịn luồng đế bỏ chặn luồng khác chương trình bị treo Khi bạn nên gọi phương thức signalAirĩ Quy tắc chung gọi signalAll bất kế trạng thái đối tượng thay đổi theo cách tác động thuận lợi tới luồng chờ Ví dụ, số dư tài khoản thay đối, luồng chờ cấp hội khác để kiểm tra số dư Trong ví dụ chúng ta, gọi signalAll hoàn tất việc chuyển tiền public void transferfint from, int to, int amount) { bankLock.lockQ; try { while (accounts [from] < amount) sufficientFunds.await(); IỊ Chuyển tiền (transfer funds) sufficientFunds.signalAHQ; } finally { bankLock.unlock(); } } 400 Lưu ý rằng, lời gọi đến phương thức signalAll khơng kích hoạt luồng chờ Nó bỏ chặn luồng chờ để chúng cạnh tranh để vào vào đối tượng sau luồng từ bỏ khóa Một phương thức khác, signal, bỏ chặn luồng đơn từ tập chờ, chọn ngẫu nhiên Cách hiệu bỏ chặn tất luồng, có mối nguy hiem Neu luồng chọn ngẫu nhiên thấy khơng thể tiếp tục, bị chặn lại lần Neu khơng có luồng khác gọi lại phương thức signal, hệ thống bế tắc (deadlock) LƯU Ý: Một luồng gọi phương thức await, signalAll, signal điều kiện sở hữu khóa điều kiện Neu bạn chạy chương trình 9.7, bạn nhận thấy khơng có sai Tổng số dư tồn mức 100.000 đô la mãi Khơng có tài khoản có số dư âm (Một lần nữa, nhấn Ctrl + c để chấm dứt chương trình.) Bạn nhận thấy rằng, chương trình chạy chậm chút - giá bạn trả cho việc bổ sung thêm chế đồng hóa Trong thực tế, việc sử dụng điều kiện xác mạo hiểm Trước bạn bất đầu cài đặt đối tượng điều kiện riêng bạn, bạn nên cân nhắc sử dụng cấu trúc mơ tả “Trình đồng hóa” (Synchronizers) Chương trình 9.8 import java.util *; import java.util.concurrentlocks ; * // Lớp biểu diễn ngân hàng với số tài khoản, sử dụng khóa để truy cập public class Bank { private final double[] accounts; private Lock bankLock; private Condition sufficientFunds; /** * Khởi tạo lớp ngân hàng * @param n: số lượng tài khoản * @param initialBalance: số dư ban đầu cho tài khoản public Bankfint n, double initialBalance) { 401 accounts = new double [n]; Arrays.fill(accounts, initialBalance); bankLock = new ReentrantLockQ; sufficientFunds = bankLockmewConditionQ; } /** * Chuyển tiền từ tài khoản sang tài khoản khác * @param from: tài khoản nguồn * @param to: tài khoản đích * @param amount: lượng tiền cần chuyển */ public void transferfint InterruptedException from, int to, double amount] { bankLock.lock(); try { while (accounts [from] < amount] sufficientFunds.awaitQ; System.out.print(Thread.currentThread(]]; accounts [from] -= amount; System.out.printf(" %10.2f from %d to %d", amount, from, to]; accounts [to] += amount; System.out.printff" Total Balance: %10.2f%n", getTotalBalancef)]; sufficientFunds.signalAllf]; } finally { bankLock.unlock(]; } } 402 throws ỵ** * Lấy tổng số dư tất tài khoản * ©return: trả tổng số dư public double getTotalBalancef) { bankLock.lock(); try { double sum = 0; for (double a: accounts) sum += a; return sum; } finally { bankLock.unlock(); } } /** * Lấy số lượng tài khoản ngân hàng * ©return: trả số lượng tài khoản public int size() { return accounts.length; } } 403 9.5.5 Từ khóa synchronized Trong phần trước, bạn thấy cách sử dụng đối tượng Lock Condition Trước xa nữa, để chúng tơi tóm tắt điểm khóa điều kiện: - Khóa bảo vệ phần mã, cho phép luồng thực thi mã thời điểm - Khóa quản lý luồng cố gắng nhập phân đoạn mã bảo vệ - Một khóa có nhiều đối tượng điều kiện liên kết - Mỗi đối tượng điều kiện quản lý luồng vào phần mã bảo vệ tiến hành Các giao diện Lock Condition cung cấp cho lập trình viên mức độ kiếm sốt cao khóa Tuy nhiên, hầu hết tình huống, bạn khơng cần điều khiển đó, bạn sử dụng chế tích họp vào ngơn ngữ Java Ke từ phiên 1.0, đối tượng Java có khóa nội Neu phương thức khai báo với từ khóa synchronized, khóa đối tượng bảo vệ tồn phương thức Khi đó, để gọi phương thức, luồng phải lấy khóa nội đối tượng Nói cách khác, đoạn mã sau: public synchronized void method^ { J _ _ tương đương với: publicvoid methodQ { this.intrinsicLock.lockQ; try{ } finally {this.intrinsicLock.unlockQ;} _ — Ví dụ, thay sử dụng khóa cách tường minh, cần khai báo phương thức transfer lóp Bank synchronized Khóa nội đối tượng có điều kiện liên kết Phương thức wait thêm luồng vào tập chờ phương thức notifyAll / notify bỏ chặn luồng chờ Nói cách khác, việc gọi phương thức wait hay notifyAll tương đương với: intrinsicCondition.awaitO; intrinsicCondition.signalAHQ; Bạn triển khai lớp Bank Java: 404 class Bank { private double [] accounts; public synchronized void transferfint from, int to, int amount) throws InterruptedException { while (accounts [from] < amount) wait(); // Chờ điều kiện khóa đối tượng nội accounts [from] -= amount; accounts [to] += amount; notifyAHQ; 11 Thông báo cho tất luồng chờ điều kiện } public synchronized double getTotalBalanceQ {■■■} } _ Như bạn thấy, sử dụng từ khóa synchronized khiến cho mã ngắn gọn nhiều Tất nhiên, đế hiếu mã này, bạn phải biết đối tượng có khóa nội khóa có điều kiện nội Khóa quản lý luồng cố gắng vào phương thức synchronized Điều kiện giúp quản lý luồng gọi phương thức wait Nó họp lệ khai báo phương thức tĩnh synchronized Neu phương thức gọi, có khóa nội đối tượng lóp liên quan Ví dụ: lớp Bank có phương thức tĩnh đồng hóa, khóa đối tượng Bank.class sể bị khóa gọi Ket là, khơng có luồng khác gọi phương thức phương thức tĩnh đồng hóa khác lớp BÀI TẬP 9.1 Tạo file MyThreadl.java thực thi giao diện Runnable thực công việc sau: - Trong phương thức run() chứa vòng lặp in 10 số tự nhiên lần in cách 500 milliseconds - Tạo object từ class MyThread Thread Thread2 với thứ tự ưu tiên tương ứng MAX PRIORITY MIN-PRIORITY - Gọi phương thức startQ cho hai luồng 405 9.2 Tạo file MyThread2.java thực theo yêu cầu: - Tạo hai luồng Thread Thread2 - Luồng Threadl in số chẵn nằm đến 10 - Luồng Thread2 in số lẻ nằm đến 10 - Viết đoạn code cho chương trình chạy xong Thread chạy tiếp sang Thread2 9.3 Tạo file MyThread3.java, gồm hai luồng Threadl Thread2 thực theo yêu cầu: - Thread 1: Hiến thị số từ đến 10 - Thread2: Dựa vào số hiển thị ỡ Theadl in tương ứng “Chằn” “Lẻ” Sử dụng phương thức wait() and notifyO từ khóa synchronized cho luồng 9.4 Viết chương trình MyThread4.java tạo mảng có 1.000.000 phần tử, sau tạo hai luồng đế xếp hai nửa mảng, cuối ghép hai mảng xếp So sánh cách làm với cách xếp trực tiếp tồn mảng 9.5 Viết chương trình MyThread5.java tạo hai luồng, luồng tìm kiếm số nguyên tố từ 1.000 đến 1.000.000 luồng tính tống giá trị số nguyên tố tìm được, ý đồng hai luồng 9.6 Viết chương trình MyThread6.java cho phép tìm kiếm song song mảng số nguyên Lóp cung cấp phương thức tĩnh sau: public ỉntparallelsearch (intx, ỉnt [] A, ỉnt numThreads) - x: số nguyên cần tìm kiếm - A: mảng số nguyên để tìm kiếm - numThreads: số lượng luồng để thực việc tìm kiếm 9.7 Tạo file My Thread?.java thực theo yêu cầu: - Thread 1: giây sinh số nguyên ngẫu nhiên khoảng từ đến 20 - Thread2: giây lấy số ngẫu nhiên mà Thread sinh tính bình phương hiển thị hình 406 TÀI LIỆU THAM KHẢO Deitel & Deitel, Java How to Program, 9th edition, Prentice Hall, 2012 Core Java Volume I-Fundamentals, Cay s Horstmann, Prentice Hall, 2016 Core Java Volume Il-Advanced Features, Cay s Horstmann, Prentice Hall, 2017 Core Java SE for the Impatient, Cay s Horstmann, 2018 An Introduction to Object-Oriented Programming With Java 5th Edition, c Thomas Wu, 2009 Kathy Sierra, Bert Bates, Head First Java, 2nd edition, O'Reilly, 2008 The Java Programming Language - Ken Arnold, James Gosling, Addison Wesley Professional, 2005 Giáo trình lý thuyết vào tập Java, Trần Tiến Dũng, NXB Lao động Xã hội, 2006 Core Java Tutorial - JoumalDev, https://www.joumaldev.com/core-javatutorial, truy cập ngày 25/5/2019 10 Java Tutorial - w3resource, https://www.w3resource.com/java-tutorial/, truy cập ngày 25/5/2019 407 BAI GIANG LAP TRINH JAVA NXB BÁCH KHOA - HÀ NỘI Ngõ 17 Tạ Quang Bửu - Hai Bà Trưng - Hà Nội ĐT: 024 38684569; Fax: 024 38684570 Website: http://nxbbk.hust.edu.vn Chịu trách nhiệm xuất bản: Giám đốc - Tổng biên tập: TS BÙI ĐỨC HÙNG Biên tập: NGUYỄN THỊ THU Sửa in: vũ THỊ HẰNG Trình bày bìa: DƯƠNG HỒNG ANH In 700 khổ (19 X 27) cm Công ty TNHH Bao bì Sao Phương Bắc, số 59 Phố Mới, thị trấn Như Quỳnh, huyện Văn Lâm, tinh Hưng Yên Số xuất bản: 2043 - 2019/CXBIPH/02 - 38/BKHN; ISBN: 978-604-95-0856-1 Số QĐXB: 294/QĐ - ĐHBK - BKHN ngày 27/12/2019 In xong nộp lưu chiểu quý I năm 2020