Hướng dẫn java vs python threads
Vì sao những ngôn ngữ như Java đòi hỏi phải code nhiều hơn Python khi thực hiện cùng một công việc? Show
Có rất nhiều lí do, nhưng đầu tiên thì tôi muốn nói rõ là tôi đã sử dụng Python một cách thành thạo được 10 năm rồi. Tôi không có vấn đề gì với Python cả, thậm chí tôi còn thấy nó rất tốt cho việc học. Đúng vậy. Nói chung là lập trình Java sẽ cần phải gõ nhiều hơn Python đấy. Nhưng nếu đó là vấn đề lớn với bạn, hãy kiếm IDE khác tốt hơn hoặc học cách đánh máy nhanh hơn. Code của Python ngắn gọn hơn, nhưng cái giá phải trả là gì? Cùng xem nhé… def getCustomer(id): Hàm này sẽ trả về gì nhỉ? Hay không trả về bất cứ gì cả? Biến “id” là kiểu gì? Số? Chuỗi? “CustomerID” object? Cùng xem Java nào… public CustomerRecord getCustomer(CustomerID id){ Số lượng code dài gấp đôi. Nhưng chúng ta có thể thấy rõ là hàm sẽ trả về kiểu nào, code làm gì trong đó. Những đoạn code của Java rõ ràng như những điều khoản được viết ra trong hợp đồng vậy. Đây điều mà Python không có. Tôi nghĩ là Python phù hợp cho việc học và có thể làm nhiều thứ cao cấp hơn nữa. Nhưng công việc gần nhất của tôi về Python đòi hỏi viết hơn 100,000 dòng code. Trong 100,000 dòng code đó, ví dụ mà tôi đưa ra ở trên sẽ xảy ra hơn 1000 lần, với hơn 1000 biến không xác định và hơn 1000 kết quả trả về cũng không xác định luôn. Chúng sẽ không được kiểm tra tại thời gian biên dịch mà là vào lúc chạy chương trình, đây là sự khác biệt quan trọng. Bug trong Python sẽ không được tìm thấy lúc biên dịch. Đọc lại lần nữa đi. Đây. thực. sự. là. một. vấn. đề. lớn. Bên cạnh việc kiểm tra kiểu dữ liệu thì Threading là 1 trong những nguyên nhân chính vì sao người ta lại sử dụng Java. Python không hỗ trợ Threading một cách hiệu quả.Lần đầu tiên đọc về nó, tôi cho rằng mình đã nhẫm lẫn chỗ nào rồi. Nhưng tiếc là tôi chả đọc sai gì cả. Tôi sẽ kết thúc câu trả lời này bằng lời khuyên của mình… Đừng quá tôn thờ bất kỳ ngôn ngữ nào cả, chúng không phải 1 thứ tôn giáo, chỉ là những công cụ mà thôi. Vài ngôn ngữ tốt hơn những ngôn ngữ khác ở mặt này, nhưng lại thua kém ở các mặt khác. Java không phải ác quỷ. Nó không hề tệ. Đơn giản là nó khác biệt với Python. Có việc thì nó thực hiện tốt hơn, có việc thì nó tệ hơn. Tôi nghĩ việc có sự gắn bó cảm xúc với ngôn ngữ đầu tiên bạn học là khá phổ biến. Nhưng cái cảm xúc đó sẽ ngăn cản bạn trở thành một lập trình viên chuyên nghiệp. Có thể bạn quan tâm:
Bài viết được sự cho phép của tác giả Giang Phan Giới thiệuThread là gì? Multi-thread là gì?Thread (luồng) về cơ bản là một tiến trình con (sub-process). Một đơn vị xử lý nhỏ nhất của máy tính có thể thực hiện một công việc riêng biệt. Trong Java, các luồng được quản lý bởi máy ảo Java (JVM). Multi-thread (đa luồng) là một tiến trình thực hiện nhiều luồng đồng thời. Một ứng dụng Java ngoài luồng chính có thể có các luồng khác thực thi đồng thời làm ứng dụng chạy nhanh và hiệu quả hơn. VD: Trình duyệt web hay các chương trình chơi nhạc là 1 ví dụ điển hình về đa luồng. + Khi duyệt 1 trang web, có rất nhiều hình ảnh, CSS, javascript… được tải đồng thời bởi các luồng khác nhau. + Khi play nhạc, chúng ta vẫn có thể tương tác được với nút điều khiển như: Play, pause, next, back … vì luồng phát nhạc là luồng riêng biệt với luồng tiếp nhận tương tác của người dùng. Tuyển dụng Java lương cao up to 2000USD Đa nhiệm (multitasking)Multitasking: Là khả năng chạy đồng thời một hoặc nhiều chương trình cùng một lúc trên một hệ điều hành. Hệ điều hành quản lý việc này và sắp xếp lịch phù hợp cho các chương trình đó. Ví dụ, trên hệ điều hành Windows chúng ta có làm việc đồng thời với các chương trình khác nhau như: Microsoft Word, Excel, Media Player, … Chúng ta sử dụng đa nhiệm để tận dụng tính năng của CPU. Đa nhiệm có thể đạt được bằng hai cách:
Đa tiến trình (multiprocessing) và đa luồng (multithreading) cả hai được sử dụng để tạo ra hệ thống đa nhiệm (multitasking). Nhưng chúng ta sử dụng đa luồng nhiều hơn đa tiến trình bởi vì các luồng chia sẻ một vùng bộ nhớ chung. Chúng không phân bổ vùng bộ nhớ riêng biệt để tiết kiệm bộ nhớ, và chuyển đổi ngữ cảnh giữa các luồng mất ít thời gian hơn tiến trình. Ưu điểm của đa luồng
Nhược điểm của đa luồng
Vòng đời (các trạng thái) của một Thread trong javaVòng đời của thread trong java được kiểm soát bởi JVM. Java định nghĩa các trạng thái của luồng trong các thuộc tính static của lớp Thread.State:
Cách tạo luồng trong JavaTrong java ta có thể tạo ra một luồng bằng một trong hai cách sau: tạo 1 đối tượng của lớp được extend từ class Thread hoặc implements từ interface Runnable. Tạo luồng bằng cách extend từ lớp ThreadĐể tạo luồng bằng cách tạo lớp kế thừa từ lớp Thread, ta phải làm các công việc sau :
package com.gpcoder.simple; public class TheadSimple extends Thread { public void run() { System.out.println("thread is running..."); } public static void main(String args[]) { TheadSimple t1 = new TheadSimple(); t1.start(); } } Lưu ý :
Tạo luồng bằng cách implement từ Interface RunnableĐể tạo luồng bằng cách hiện thực từ Interface Runnable, ta phải làm các công việc sau :
package com.gpcoder.simple; public class RunnableSimple implements Runnable { public void run() { System.out.println("thread is running..."); } public static void main(String args[]) { RunnableSimple runable = new RunnableSimple(); Thread t1 = new Thread(runable); t1.start(); } } Khi nào implements từ interface Runnable?+ Cách hay được sử dụng và được yêu thích là dùng interface Runnable, bởi vì nó không yêu cầu phải tạo một lớp kế thừa từ lớp Thread. Trong trường hợp ứng dụng thiết kế yêu cầu sử dụng đa kế thừa, chỉ có interface mới có thể giúp giải quyết vấn đề. Ngoài ra, Thread Pool rất hiểu quả và có thể
được cài đặt, sử dụng rất hơn giản. Ví dụ minh họa sử dụng đa luồngVí dụ Tạo luồng bằng cách extend từ class ThreadTạo luồng extend từ class Thead package com.gpcoder.flow; public class ThreadDemo extends Thread { private Thread t; private String threadName; ThreadDemo(String name) { threadName = name; System.out.println("Creating " + threadName); } @Override 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(); } } } Chương trình sử dụng đa luồng: package com.gpcoder.flow; public class ThreadDemoTest { public static void main(String args[]) { System.out.println("Main thread running... "); ThreadDemo T1 = new ThreadDemo("Thread-1-HR-Database"); T1.start(); ThreadDemo T2 = new ThreadDemo("Thread-2-Send-Email"); T2.start(); System.out.println("==> Main thread stopped!!! "); } } Kết quả thực thi chương trình trên: Main thread running... Creating Thread-1-HR-Database Starting Thread-1-HR-Database Creating Thread-2-Send-Email Starting Thread-2-Send-Email ==> Main thread stopped!!! Running Thread-1-HR-Database Running Thread-2-Send-Email Thread: Thread-2-Send-Email, 4 Thread: Thread-1-HR-Database, 4 Thread: Thread-1-HR-Database, 3 Thread: Thread-2-Send-Email, 3 Thread: Thread-2-Send-Email, 2 Thread: Thread-1-HR-Database, 2 Thread: Thread-2-Send-Email, 1 Thread: Thread-1-HR-Database, 1 Thread Thread-2-Send-Email exiting. Thread Thread-1-HR-Database exiting. Kết quả chương trình trên được giải thích thông qua hình bên dưới: Ví dụ Tạo luồng bằng cách implement từ Interface RunnableTạo luồng implement từ Interface Runnable package com.gpcoder.flow; class RunnableDemo implements Runnable { private Thread t; private String threadName; RunnableDemo(String name) { threadName = name; System.out.println("Creating " + threadName); } @Override 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(); } } } Chương trình sử dụng đa luồng: package com.gpcoder.flow; public class RunnableDemoTest { public static void main(String args[]) { System.out.println("Main thread running... "); RunnableDemo R1 = new RunnableDemo("Thread-1-HR-Database"); R1.start(); RunnableDemo R2 = new RunnableDemo("Thread-2-Send-Email"); R2.start(); System.out.println("==> Main thread stopped!!! "); } } Kết quả thực thi chương trình trên: Main thread running... Creating Thread-1-HR-Database Starting Thread-1-HR-Database Creating Thread-2-Send-Email Starting Thread-2-Send-Email ==> Main thread stopped!!! Running Thread-1-HR-Database Running Thread-2-Send-Email Thread: Thread-1-HR-Database, 4 Thread: Thread-2-Send-Email, 4 Thread: Thread-1-HR-Database, 3 Thread: Thread-2-Send-Email, 3 Thread: Thread-1-HR-Database, 2 Thread: Thread-2-Send-Email, 2 Thread: Thread-1-HR-Database, 1 Thread: Thread-2-Send-Email, 1 Thread Thread-1-HR-Database exiting. Thread Thread-2-Send-Email exiting. Kết quả chương trình trên được giải thích thông qua hình bên dưới: Các phương thức của lớp Thread thường hay sử dụng
Một số thông tin liên quan đến luồngĐịnh danh của luồng (ThreadId)ThreadId là định danh của luồng, nó dùng để phân biệt với các luồng khác cùng tiến trình hoặc cùng tập luồng. Đây là thông số mà máy ảo java tự tạo ra khi ta tạo luồng nên ta không thể sửa đổi cũng như áp đặt thông số này khi tạo luồng. Nhưng ta có thể lấy được nó thông qua phương thức getId() của lớp Thread Tên của luồng (ThreadName)ThreadName là tên của luồng, đây là thuộc tính mà ta có thể đặt hoặc không đặt cho luồng. Nếu ta không đặt cho luồng thì máy ảo java sẽ tự đặt với quy tắc sau: “Thread-” + Thứ tự luồng được tạo ra, bắt đầu từ 0. Độ ưu tiên của luồng (Priority)Như đã nói ở phần trước, mỗi luồng có 1 độ ưu tiên nhất định. Đây sẽ là thông số quyết định mức ưu tiên khi cấp phát CPU cho các luồng. Trong java, đế đặt độ ưu tiên cho 1 luồng ta dùng phương thức: void setPriority(int newPriority)
Java có định nghĩa sẵn 3 mức ưu tiên chuẩn như sau:
Để lấy độ ưu tiên của 1 luồng, ta dùng phương thức: int getPriority() Ví dụ minh họaWorkingThread.java package com.gpcoder.info; public class WorkingThread extends Thread { public WorkingThread(String name) { super(name); } public void run() { for (int i = 0; i < 5; i++) { System.out.printf("Luồng: %s có độ ưu tiên là %d \n", getName(), getPriority()); } } } ThreadInfoExample.java package com.gpcoder.info; public class ThreadInfoExample { public static void main(String[] args) { Thread t1 = new WorkingThread("Luồng 1"); Thread t2 = new WorkingThread("Luồng 2"); Thread t3 = new WorkingThread("Luồng 3"); System.out.println("ID luồng 1: " + t1.getId()); System.out.println("ID luồng 2: " + t2.getId()); System.out.println("ID luồng 3: " + t3.getId()); t1.setPriority(1); t2.setPriority(5); t3.setPriority(10); t1.start(); t2.start(); t3.start(); } } Kết quả thực thi chương trình trên: ID luồng 1: 10 ID luồng 2: 11 ID luồng 3: 12 Luồng: Luồng 2 có độ ưu tiên là 5 Luồng: Luồng 2 có độ ưu tiên là 5 Luồng: Luồng 2 có độ ưu tiên là 5 Luồng: Luồng 2 có độ ưu tiên là 5 Luồng: Luồng 2 có độ ưu tiên là 5 Luồng: Luồng 1 có độ ưu tiên là 1 Luồng: Luồng 3 có độ ưu tiên là 10 Luồng: Luồng 3 có độ ưu tiên là 10 Luồng: Luồng 3 có độ ưu tiên là 10 Luồng: Luồng 3 có độ ưu tiên là 10 Luồng: Luồng 3 có độ ưu tiên là 10 Luồng: Luồng 1 có độ ưu tiên là 1 Luồng: Luồng 1 có độ ưu tiên là 1 Luồng: Luồng 1 có độ ưu tiên là 1 Luồng: Luồng 1 có độ ưu tiên là 1 Sử dụng phương thức sleep()Phương thức sleep() của lớp Thread được sử dụng để tạm ngừng một thread cho một khoảng thời gian nhất định. Ví dụ chương trình in ra số từ 1 – 5, tạm ngừng 500 ms trước khi in chữ số tiếp theo. package com.gpcoder.sleep; public class SleepMethodExample extends Thread { public void run() { for (int i = 1; i <= 5; i++) { System.out.println(i); try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } public static void main(String args[]) { SleepMethodExample t1 = new SleepMethodExample(); t1.start(); } } Sử dụng join() và join(long)join() : thông báo rằng hãy chờ thread này hoàn thành rồi thread cha mới được tiếp tục chạy. Ví dụ: package com.gpcoder.join; public class UsingJoinMethod extends Thread { public UsingJoinMethod(String name) { super(name); } @Override public void run() { System.out.println(getName()); for (int i = 1; i <= 5; i++) { try { System.out.print(i + " "); Thread.sleep(300); } catch (InterruptedException ie) { System.out.println(ie.toString()); } } System.out.println(); } public static void main(String[] args) throws InterruptedException { UsingJoinMethod t1 = new UsingJoinMethod("Thread 1"); UsingJoinMethod t2 = new UsingJoinMethod("Thread 2"); t1.start(); t1.join(); t2.start(); System.out.println("Main Thread Finished"); } } Thực thi chương trình trên: Thread 1 1 2 3 4 5 Main Thread Finished Thread 2 1 2 3 4 5 join(long) : Thread cha cần phải đợi millisecond mới được tiếp tục chạy, kể từ lúc gọi join(long). Nếu tham số millis = 0 nghĩa là đợi cho tới khi luồng này kết thúc. package com.gpcoder.join; public class UsingJoinMethod2 extends Thread { public UsingJoinMethod2(String name) { super(name); } @Override public void run() { System.out.println(getName()); for (int i = 1; i <= 5; i++) { try { System.out.print(i + " "); Thread.sleep(300); } catch (InterruptedException ie) { System.out.println(ie.toString()); } } System.out.println(); } public static void main(String[] args) throws InterruptedException { UsingJoinMethod2 t1 = new UsingJoinMethod2("Thread 1"); UsingJoinMethod2 t2 = new UsingJoinMethod2("Thread 2"); t1.start(); // Main Thread phải chờ 450ms mới được tiếp tục chạy. // Không nhất thiết phải chờ Thread t1 kết thúc t1.join(450); t2.start(); System.out.println("Main Thread Finished"); } } Thực thi chương trình trên: Thread 1 1 2 Main Thread Finished Thread 2 1 3 2 4 3 5 4 5 Xử lý ngoại lệ cho ThreadPhương thức Thread.setDefaultUncaughtExceptionHandler() thiết lập mặc định xử lý khi luồng đột ngột chấm dứt do một ngoại lệ xảy ra mà không có xử lý khác đã được xác định cho luồng đó. Ví dụ: package com.gpcoder.exception; import java.util.Random; public class WorkingThread implements Runnable { @Override public void run() { while (true) { processSomething(); } } private void processSomething() { try { System.out.println("Processing working thread"); Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } Random r = new Random(); int i = r.nextInt(100); if (i > 70) { throw new RuntimeException("Simulate an exception was not handled in the thread"); } } } Chương trình minh họa xử lý Thread Exception package com.gpcoder.exception; public class ThreadExceptionDemo { public static void main(String[] args) { System.out.println("==> Main thread running..."); Thread thread = new Thread(new WorkingThread()); Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { @Override public void uncaughtException(Thread t, Throwable e) { System.out.println("#Thread: " + t); System.out.println("#Thread exception message: " + e.getMessage()); } }); thread.start(); System.out.println("==> Main thread end!!!"); } } Thực thi chương trình trên: ==> Main thread running... ==> Main thread end!!! Processing working thread Processing working thread Processing working thread Processing working thread Processing working thread Processing working thread #Thread: Thread[Thread-0,5,main] #Thread exception message: Have a problem... Trên đây là những kiến thức cơ bản về đa luồng (Multi-thread) trong java. Chúng ta sẽ tiếp tục tìm hiểu về các vấn đề khác của đa luồng trong Java ở các bài viết tiếp theo. Cám ơn các bạn đã quan tâm và theo dõi bài viết. Tài liệu tham khảo:
Bài viết gốc được đăng tải tại gpcoder.com Có thể bạn quan tâm:
Xem thêm các việc làm Java hấp dẫn tại TopDev |