Java: Question and answer for interviewing

Nguồn: https://www.edureka.co/blog/interview-questions/java-interview-questions/ và https://congdongjava.com/forum/threads/java-thread-luồng-trong-java.714/

Cảm ơn 2 nguồn rất nhiều, thông tin rất rõ và bổ ích

  1. Static là gì? Nếu để static thì sao mà non static thì sao? Trả lời: Static là 1 keyword của java để định nghĩa method hoặc variable có thể được truy cập sử dụng mà không cần tạo instance của Class. Vd: ta có thể sử dụng static method B của class A thông qua cách gọi A.B() mà ko cần tạo instance như “a = new A(); a.B();”
  2. Hàm main trong 1 class là gì? Tại sao cần hàm main()? Trả lời: Hàm main là 1 hàm mặc định trong 1 class, hàm main này sẽ được JVM tìm và phát hiện ra để chạy ứng dụng. It is the method where the main execution occurs.
  3. Tại sao Java không phải là 100% OOP? Trả lời: Bởi vì trong java có các kiểu dữ lieu nguyên thủy Boolean, long, string, int, … không phải là 1 object.
  4. Constructor trong Java là gì? Trả lời: constructor là 1 block of code thường được xài để khởi tạo object, Constructor phải có tên giống với tên của class và không có kiểu trả về, nó được tự động gọi khi object được tạo. Có 2 kiểu constructor: default(constructor rỗng, ko có gì) và parameterized(khởi tạo có biến).
  5. Singleton class là gì và làm thế nào để tạo 1 class singleton? Trả lời: Singleton là một trong nhưững design pattern đơn giản nhất, để đảm bảo trong 1 chương trình chỉ có 1 instance của 1 class được tạo. Singleton class có thể được tạo bang cách cho constructor private, và tạo 1 method public static getInstance() mà có thể access từ client đêể gọi và method này sẽ tạo instance nếu chưa khởi tạo và ngược lại. VD:


class Singleton {
private static Singleton instance;

private Singleton() {

}

public static synchronized Singleton getInstance(){

if (instance == null)
instance = new Singleton();

return instance; } … public void doSomething()
{

}
}

Và ta gọi bang cách: “Singleton.getInstance().doSomething();”

6. Các tính đặc thù của OOP là gì? Trả lời: OOP có 4 tính đặc thù là: kế thừa, đa hình, trừu tượng, đóng gói.

  • Tính đa hình có thêể được định nghĩa như sau: “one interface, many implementations”. VD: khi ta sử dụng 1 class interface cha có 1 method và class này được kế thừa từ 2 class con. Các class con này kế thừa method của class cha và tự định nghĩa những giá trị trả về từ class này. VD cụ thể: ta có 3 lớp Hình, Hình vuông, Hình tròn. Trong đó lớp hình là lớp cha của 2 lớp còn lại có phương thức là tính diện tích cùng là một phương thức tính diện tích, cùng trả về diện tích của hình nhưng luồng xử lý tì hoàn toàn khác nhau -> đó là tính đa hình hóa trong hướng đối tượng.
  • Tính đóng gói: Tính chất này không cho phép người sử dụng các đối tượng thay đổi trạng thái nội tại của một đối tượng. Chỉ có các phương thức nội tại của đối tượng cho phép thay đổi trạng thái của nó. Việc cho phép môi trường bên ngoài tác động lên các dữ liệu nội tại của một đối tượng theo cách nào là hoàn toàn tùy thuộc vào người viết mã. Đây là tính chất đảm bảo sự toàn vẹn, bảo mật của đối tượng
  • Tính kế thừa: Tính chất này cho phép một đối tượng có thể có được các đặc tính (thuộc tính, phương thức) mà đối tượng khác đã có thông qua kế thừa(extends). Điều này cho phép các đối tượng chia sẻ hay mở rộng các đặc tính sẵn có mà không phải tiến hành định nghĩa lại
  • Tính trừu tượng: Chưa biết rõ.

7. Method overriding và overloading là gì và phân biệt chúng như thế nào? Trả lời:

  • Method overloading là các method có cùng tên nhưng khác nhau ở số biến truyền vào hoặc cùng số biến nhưng khác kiểu và thứ tự. Method overloading có thể không cần kế thừa vẫn gọi dung được, và method này không thể phát hiện kiểu trả về.
  • Method overriding: là class con có cùng method với tên going, số biến và kiểu biến going và cùng kiểu trả về như class cha. Method này luôn cần phải kế thừa từ class cha.

8. Chúng ta có thể overriding private hoặc static method trong java được không? Trả lời: Không thể. Nếu chúng ta tạo 1 method giống hoàn toàn với class cha thì method của class cha sẽ bị giấu đi, và sử dụng method của class con.

9 . Thế nào là đa kế thừa, và nó có được hỗ trợ trong Java không? Trả lời: Nếu 1 class con được kế thừa nhiều tính năng từ nhiều class thì đó là đa kế thừa. Trong java không hỗ trợ đa kế thừa. Vấn đề với đa kế thừa là nếu nhiều thằng class cha có cùng tên method thì trong quá trình chạy compiler sẽ khó quyết định method nào được thực hiện từ class con.

10. Mục đích của các keyword final, finally, finalize? Trả lời:

  • Final thường được dung để hạn chế class, method và variable. Final class không thể được kế thừa, final method không thể được override và final variable không thể bị thay đổi giá trị. VD:
class FinalVarExample {
public static void main( String args[])
{
final int a=10;   // Final variable
a=50;             //Error as value can't be changed
}
  • Finally thường được dung để đặt các code quan trọng, nó sẽ được thực hiện để kiểm tra xem exception đã được xử lí hay chưa. VD:
class FinallyExample {
public static void main(String args[]){
try {
int x=100;
}
catch(Exception e) {
System.out.println(e);
}
finally {
System.out.println("finally block is executing");}
}}
}
  • Finalize is used to perform clean up processing just before object is garbage collected.

Thread tất tần tật trong java:

Thread là một dòng các điều khiển trong một process hay một ứng dụng. Nguyên văn là : Threads are multiple flows of control within a single program or process.

Với cơ chế multithreading ứng dụng của bạn có thể thực thi đồng thời nhiều dòng lệnh cùng lúc. Có nghĩa là bạn có thể làm nhiều công việc đồng thời trong cùng một ứng dụng của bạn. Có thể hiểu một cách hết sức đơn giản : hệ điều hành với cơ chế đa nhiệm cho phép nhiều ứng dụng chạy cùng lúc. Thì với cơ chế đa luồng, mỗi ứng dụng của bạn có thể thực hiện được nhiều công việc đồng thời.

Bạn sẽ hỏi tại sao không dùng nhiều processes , sao không là multiprocessing mà lại cần đến multithreading ?

Câu trả lời đơn giản nhất là: Việc tạo ra và quản lý các process đòi hỏi nhiều tài nguyên của hệ thống (cả ram và CPU) nhiều hơn rất nhiều so với việc tạo ra một thread. Trong khi đó bạn có thể chỉ cần tạo ra một thread để thực hiện song song một công việc hết sức đơn giản cùng với một công việc chính.

Bạn viết một ứng dụng Java trên bất kỳ nền tảng nào. Khi ứng dụng bạn chạy thì thực sự đã có một bản sao của JVM khởi động và ứng dụng của bạn là một thread nếu bạn không dùng multithreading hoặc là nhiều threads nếu bạn dùng multithreading.
Tạo một thread

Như đã nói, mỗi khi chạy một ứng dụng trong java thì bạn đã có một thread. Đây là thread chính, nó thực thi các dóng lệnh trong method : public static void main . Đây là một điểm nhập bắt buộc cho mọi ứng dụng độc lập.

Để tạo ra một thread khác ngoài thread chính trên, Java cung cấp cho chúng ta hai cách :

– Tạo ra một lớp con của lớp Thread (java.lang.Thread)

– Tạo ra một lớp hiện thực interface Runnable

Chúng ta sẽ tìm hiểu lần lược hai cách trên.

Tạo một lớp con của lớp java.lang.Thread

Bạn khai báo như sau :

class A extends Thread {

public void run() {

… // code for the new thread to execute

}

}

A a = new A(); // create the thread object

a.start(); // start the new thread executing

Với cách này các dòng lệnh của bạn sẽ được đặt trong method run. Method này được override method nguyên thuỷ của lớp Thread.

Sau đó bạn sẽ tạo ra một đối tượng từ lớp của bạn.

Bạn gọi phương thức start từ đối tượng đó. Lúc này thread của bạn chính thức được tạo ra và phương thức start sẽ tự gọi method run của bạn và thực thi các dòng lệnh mà bạn đã đặt tả.

Chú ý rằng: method start là method của hệ thống, nó có nhiệu vụ cấp phát bộ nhớ, tạo ra một thread và gọi hàm run của bạn. Vì thế bạn không nên override phương thức này. Điều này có thể dẫn đến ko tạo được thread.
Hiện thực interface Runnable

Bạn khai báo như sau:

class B extends … implements Runnable {

public void run() {

… // code for the new thread to execute

}

}

B b = new B(); // create the Runnable object

Thread t = new Thread(b); // create a thread object

t.start(); // start the new thread

Cũng giống như cách trên, dòng lệnh của bạn đặt trong method run (có thể gọi đến các phương thức khác, nhưng phải bắt đầu trong phương thức này)

Sau đó bạn tạo một đối tượng B từ lớp đã hiện thực interface Runnable, tạo thêm một đối tượng t của lớp Thread với thông số cho constructor là đối tượng B.

Sau đó khi bạn gọi phương thức t.start() thì chính thức thread được tạo ra và phương thức run của bạn sẽ được triệu gọi một cách tự động.

Bạn sẽ hỏi tại cách thứ hai vẫn phải tạo ra một đối tượng Thread. Vậy tại sao lại đưa ra hai cách hiện thực làm gì ?

Câu trả lời là :

– Bản thân ngôn ngữ Java không hỗ trợ đa thừa kế . Bạn chỉ có thể extends từ một lớp duy nhất. Nhưng bạn lại có thể implements cùng lúc nhiều interface. Khi mà lớp của bạn đã [extends] một lớp nào đó rồi (vd : Applet), thì bạn chỉ có thể implements Runnable để tạo ra Thread.

– Việc extends lớp Thread có thể dẫn đến rủi ro là bạn override các method start, stop, … thì có thể làm cho việc tạo thread là không thể.

Một lời khuyên là: bạn nên tạo ra một lớp hiện thực interface Runnable (cách thứ hai) khi muốn tạo ra một Thread. Chương trình của bạn sẽ trong sáng và dễ tìm lỗi hơn.

Các constructor cho lớp Thread

public Thread ()

– Tạo ra một đối tượng lớp Thread.

– Constructor này có tác dụng giống như Thread(null, null, gname) với gname là một tên được phát sinh tự động bởi JVM (máy ảo java) ở dạng Thread-n , với n là một số nguyên.

public Thread(Runnable target)

– Tạo ra một đối tượng lớp Thread.

– Constructor này có tác dụng giống như Thread(null, target, gname) với gname là tên được phát sinh tự động bởi JVM (máy ảo java) ở dạng Thread-n , với n là một số nguyên.

public Thread(ThreadGroup group, Runnable target)

– Tạo ra một đối tượng lớp Thread.

– Constructor này có tác dụng giống như Thread(group, target, gname) với gname là tên được phát sinh tự động bởi JVM (máy ảo java) ở dạng Thread-n , với n là một số nguyên.

– Constructor này có thể phát sinh một ngoại lệ SecurityException nếu như thread hiện tại không có quyền tạo một thread mới trong nhóm group.

public Thread(String name)

– Tạo ra một đối tượng lớp Thread.

– Constructor này có tác dụng giống như Thread(null, null, name).

public Thread(ThreadGroup group, String name)

– Tạo ra một đối tượng lớp Thread.

– Constructor này có tác dụng giống như Thread(group, null, name).

– Constructor này có thể phát sinh một ngoại lệ SecurityException nếu như thread hiện tại không có quyền tạo một thread mới trong nhóm group.

public Thread(Runnable target, String name)

– Tạo ra một đối tượng lớp Thread.

– Constructor này có tác dụng giống như Thread(null, target, name).

public Thread(ThreadGroup group, Runnable target, String name)

– Tạo ra một đối tượng lớp Thread.

– group là nhóm các thread mà thread được tạo mới này sẽ được thêm vào.

– target là đối tượng cần chạy. Tức là trong đối tượng này có method run, chứa các dòng lệnh cần thực thi của chúng ta.

– name là tên của thread.

– Nếu group là null và có một bộ quản lý bảo mật security manager(ta thiết lập cho JVM, mặc định thì không có) thì gruop được xác định bởi method getThreadGroup của security manager. Nếu group null và không có security manager hay phương thức getThreadGroup trả về null thì group là nhóm mà thread đang hoạt động thuộc về.

– Nếu target là null thì sau khi được khởi hoạt, method run của lớp Thread sẽ được gọi. Nếu target không null thì sau khi được khởi hoạt thì method run của target sẽ được gọi.

– Độ ưu tiên (priority) của thread mới sẽ được thiết lập bằng với độ ưu tiên của thread tạo ra nó.

– Constructor này có thể phát sinh một ngoại lệ SecurityException nếu như thread hiện tại không có quyền tạo một thread mới trong nhóm group.

Chi tiết hơn bạn có thể xem ở Java API của bộ JDK

Một số phương thức chính của lớp Thread

public static Thread currentThread()

– Phương thức này là một phương thức tĩnh. Có nghĩa là bạn có thể gọi nó ở bất đâu mà không cần phải tạo một đối tượng của lớp Thread.

– Cú pháp để gọi phương thức này là : Thread.currentThread()

– Phương thức này trả về một đối tượng của lớp Thread. Đối tượng này thể hiện cho thread mà đang thực thi dòng lệnh này.

public long getId()

– Phương thức này trả về một số nguyên là định danh của thread.

– Con số này là do máy ảo Java (JVM) tạo ra.

public final String getName()

– Phương thức này trả về tên của thread.

public final void setName(String name)

– Thay đổi tên của thread bằng tên name.

public Thread.State getState()

– Trả về trạng thái hiện tại của thread.

– Là một hằng của lớp Thread.

– Các giá trị có thể là :

+ NEW : thread chưa được khởi hoạt.

+ RUNNABLE : thread đang hoạt động trong JVM.

+ BLOCKED : thread chờ một monitor để unlock một đối tượng mà nó cần.

+ WAITING : thread chờ không giới hạn cho đến khi một thread khác đánh thức nó.

+ TIMED_WAITING : thread chờ trong một thời gian nhất định, hoặc là có một thread khác đánh thức nó.

+ TERMINATED : thread đã kết thúc công việc của nó.

public static void yield()

– Đây là một phương thức tĩnh.

– Phương thức này sẽ làm cho thread hiện thời tạm ngưng hoạt động để nhường cho một thread khác hoạt động.

public static void sleep(long millis) throws InterruptedException

public static void sleep(long millis, int nanos) throws InterruptedException

– Đây là một phương thức tĩnh.

– Phương thức này làm cho thread hiện tại ngừng hoạt động trong một thời gian millis milliseconds.

– Phương thức này có thể phát sinh một ngoại lệ InterruptedException nếu có một thread nào đó làm ngưng hoạt động thread này. (Nhưng không hợp lệ, tức là không dùng các phương thức được cho phép).

public void start()

– Phương thức này chính thức tạo ra một đối tượng thread. Và JVM sẽ tự động gọi phương thức run của đối tượng này nếu nhưng target là null. Hoặc sẽ gọi phương thức run của target nếu như target khác null.

– Tuyến được bắt đầu hoạt động sau khi phương thức này được gọi thành công.

– Phương thức này có thể phát sinh một ngoại lệ IllegalThreadStateException nếu thread này đã được khởi hoạt.

public final boolean isAlive()

– Phương thức này kiểm tra xem thread có còn hiệu lực hay không (còn sống).

– Một thread còn sống khi mà nó đã được khởi hoạt và chưa kết thúc công việc của nó.

public final ThreadGroup getThreadGroup()

– Trả về nhóm Thread mà thread này thuộc về

public final void join(long millis) throws InterruptedException

public final void join(long millis, int nanos) throws InterruptedException

public final void join() throws InterruptedException

– Đây là phương thức được gọi bởi một thread khác.

– Phương thức này làm cho thread gọi phải ngưng hoạt động và chờ trong một khoảng thời gian millis millisecond hoặc chờ trong khoảng thời gian millis millisecond và nanos nanosseconds, hoặc chờ cho đến khi thread này kết thúc thì mới tiếp tục hoạt động.

– Phương thức này có thể phát sinh một ngoại lệ InterruptedException nếu nó bị một thread khác làm ngưng hoạt động.

public String toString()

– Trả về một thể hiện dạng String của thread này.

– Thể hiện này bao gồm tên, độ ưu tiên và nhóm.

public final void stop()

public final void stop(Throwable obj)

public void destroy()

public final void suspend()

public final void resume()

– Các methods này đều được khuyến cáo là không nên dùng. Sẽ bị bỏ trong các phiên bản sau của bộ JRE và JDK.

– Bởi vì các methods này làm cho các monitor của hệ thống (được JVM tạo ra để giám sát các đối tượng của người dùng) bị giải phóng. Làm cho các đối tượng không được thống nhất và dẫn đến các lỗi không mong muốn, không an toàn khi sử dụng.

Tập tin đính kèm DemoThreads.jar (19921 bytes):

http://www.javavietnam.org/javavn/mvnforum/getattachment?attach=1535

Tập tin đính kèm DemoThreads.zip (26938 bytes):

http://www.javavietnam.org/javavn/mvnforum/getattachment?attach=1536

Ở phần trước , mình đã giới thiệu sơ qua về Thread và cách tạo một Thread. Bây giờ mình sẽ giới thiệu thêm một số vấn đề liên quan khi lập trình với Java Threads.
Thread Group

– ThreadGroup là một lớp trong gói java.lang.

– Lớp này cho phép chúng ta quản lý một nhóm các Threads cho ứng dụng của chúng ta.

– Các threads được gom thành một nhóm thông thường dựa trên một mối quan hệ nào đó giữa chúng.Vd như: người tạo ra chúng, chức năng chính của chúng, hay khi nào chúng sẽ được start hay stop.
Tạo một ThreadGroup

ThreadGroup group = new ThreadGroup( “A group”);

Thread one = new Thread(group, “one”);

Thread two = new Thread(group, “two”);

Một số phương thức liên quan

public int activeCount()

– Trả về số thread hiện tại có trong ThreadGroup.
public final int getMaxPriority()

– Trả về độ ưu tiên cao nhất của các threads trong nhóm.

– Một thread thuộc nhóm này thì không thể có độ ưu tiên cao hơn độ ưu tiên cao nhất của nhóm.

public final void setMaxPriority(int pri)

– Thiết lập độ ưu tiên cao nhất cho nhóm.

– pri phải nằm trong khoảng Thread.MIN_PRIORITY Thread.MAX_PRIORITY.

public final void checkAccess()

– Kiểm tra xem thread đang chạy có quyền thay đổi nhóm thread này hay không.

public final boolean isDaemon()

– Kiểm tra xem nhóm có phải là nhóm các Daemon Thread hay không.

– Daemon thread sẽ được đề cập tới.

public final void setDaemon(boolean daemon)

– Thiết lập nhóm thread là Daemon Thread.

Chi tiết hơn bạn có thể xem ở Java API

Thread Priority

– Mỗi một thread trong java đều có một độ ưu tiên nhất định.

– Độ ưu tiên này nằm trong khoảng Thread.MIN_PRIORITY (0) và MAX_PRIORITY (10).

– Độ ưu tiên của một thread được tạo ra sẽ mặc định là bằng với độ ưu tiên với thread tạo ra nó.

– Việc thiết lập cũng như lấy về độ ưu tiên của một thread được thực hiện thông qua hai phương thức:

+ public final void setPriority(int newPriority)

+ public final int getPriority()
Daemon Thread

– Mọi thread đều có thể là Daemon Thread.

– Daemon threads là các threads có nhiệm cụ cung cấp dịch vụ cho các threads khác cùng hoạt động trong cùng một process.

– Một điều quan trọng là : máy ảo JVM sẽ tự kết thúc hoạt động nếu như tất cả các thread trong ứng dụng đều là Daemon Threads.

Một câu hỏi đặt ra là : Tại sao lại cần Daemon Thread trong khi thread bình thường vẫn có thể cung cấp dịch vụ cho thread khác?

Trả lời :

– Ví dụ bạn có một thread A có nhiệm vụ cung cấp dịch vụ trao đổi dữ liệu với một máy khác từ xa thông qua mạng internet. Khi đó thread A phải có nhiệm vụ chờ yêu cầu trao đổi dữ liệu từ một thread nào đó. Vậy bạn không biết lúc nào sẽ có yêu cầu trao đổi dữ liệu, khi nào sẽ không còn yêu cầu nào nữa.

– Khi thiết lập A là Daemon thread thì khi chắc chắn không còn yêu cầu nào nữa, tức là không còn thread nào sử dụng dịch vụ này nữa. JVM sẽ kết thúc hoạt động của thread A và kết thúc hoạt động của ứng dụng.

– Để thiết lập và kiểm tra một thread có phải là Daemon Thread hay không bạn có thể dùng :

+public final void setDaemon(boolean on)

+ public final boolean isDaemon()

Synchronization

– Khi tạo ra nhiều thread hoạt động song song độc lập (tức là không có dữ liệu chia sẻ) thì không có vấn đề gì.

– Tuy nhiên khi hai hay nhiều thread cùng sử dụng chung một biến hay một phương thức thì : bởi vì các thread trong một Process có thể được thực thi đồng thời (hệ thống nhiều CPU) hoặc được luân phiên gọi trong một thời gian rất ngắn (hệ thống đơn CPU) cho nên việc sử dụng dữ liệu chia sẻ là gần như đồng thời. Điều này dẫn đến vấn về : Race condition.

– Race condition (tạm dịch là điều kiện tranh chấp) : xảy ra khi có hai hày nhiều thread cùng chia sẻ dữ liệu, và khi chúng cùng đọc , cùng ghi dữ liệu chia sẻ đó đồng thời. Kết quả nhận được sẽ phụ thuộc vào tác động lên biến chia sẻ là cái gì và lúc nào. Và người lập trình không thể biết được chính xác điều gì xảy ra.

– Java đưa ra một cách giải quyết là dùng từ khoá synchronized cho phương thức hay đoạn mã mà bạn cần bảo vệ .

Synchronized Method

Bạn khai báo như sau :

public synchronized void protectedMethod(object obj)

– Method protectedMethod sẽ được đảm bảo thực thi tuần tự.

– Nghĩa là khi có 2 thread A và B gọi method protectedMethod thì nếu method A gọi trước thì khi nào method protectedMethod thực thi xong thì thread B mới được gọi. Và trong thời gian đó thì thread B phải chờ.

Ví dụ:

class Test {

static int i = 0, j = 0;

static void one() { i++; j++; }

static void two() {

System.out.println(“i=” + i);

//Do something

System.out.println(“j=” + j);

}

}

– Khi thread A gọi method one. Thread B gọi method two.

– Nhưng ở khoảng giữ hai dòng lệnh xuất method B làm một công việc gì đó khá lâu. Trong khoảng thời gian đó method A có thể được gọi nhiều lần.

– Khi đó giá trị i và j được xuất ra là không theo ý bạn. Tức là giá trị j sẽ lớn hơn giá trị i. Bạn có “cảm giác” j được cộng trước i ( thực tế i vẫn được cộng trước).

– Để đảm bảo i và j được xuất ra có giá trị luôn bằng nhau. Ta dùng từ khoá synchronized như sau

class Test {

static int i = 0, j = 0;

static synchronized void one() { i++; j++; }

static synchronized void two() {

System.out.println(“i=” + i);

//Do something

System.out.println(“j=” + j);

}

}

– Khi đó cho dù method two thực hiện một công việc lâu đến thế nào thì method one sẽ không được gọi lần nữa cho đến khi method two thực hiện xong.

– Sở dĩ ta có kết quả như vậy và bởi vì khi method two được gọi thì từ khoá synchronized se khiến cho đối tượng của lớp Test bị khoá. Khi đó một thread khác không thể sử dụng đối tượng này nữa (gọi method two hay one) và thread này phải chờ.

Synchronized Statements

– Bạn khai báo như sau :

synchronized (someObject) {

// this code will execute in one thread at a

//time and someObject will be locked.

}

– Đối tượng someObject sẽ bị khoá và đoạn mã trong khối này sẽ được thưc thi tuần tự. Tuần tự ở đây có nghĩa là nếu có 2 thread cùng thực thi đoạn mã trên thì nếu A đến trước thì A thực thi xong thì B mới được thực thi.

– Chú ý rằng chỉ có đoạn mã trong khối này mới được thực thi tuần tự (tuần tự theo nghĩa trên).

Wait and Notify

– Như bạn đã biết bản thân ngôn ngữ Java hỗ trợ multithreading. Điều này được thấy rõ ràng nhất thông qua việc lớp Object có các phương thức wait() , notify() và notifyAll().

– Như phần trước đã nói từ khoá synchronized sẽ làm cho một đối tượng bị khoá và các thread khác phải chờ nếu muốn sử dụng đối tượng này.

– Vậy nếu thread A đã khoá đối tượng obj nhưng trong quá trình xử lý của nó A cần obj được cập nhật bởi một thread B khác, rồi dựa trên giá trị này A mới xử lý tiếp.

– Phương thức wait() cho phép ta làm điều này.

– wait() làm cho thread hiện tại (thread đang khoá đối tượng obj) phải tạm ngưng hoạt động, đồng thời đối tượng obj tạm thời được mở khoá và cho phép các thread khác trong hàng đợi sử dụng obj được hoạt động.

– notify() sẽ làm cho một thread đang chờ kết quả từ obj (thread đã gọi wait()) sẽ được thực thi tiếp (tiếp tục khoá obj). Với phương thức notify() thì thread được chọn đánh thức là ngẫu nhiên tuỳ ý. do đó có thể dẫn đến deadlock.

– notifyAll() sẽ làm cho tất cả các thread chờ được hoạt động (do obj bị khoá) sẽ đều có cơ hội hoạt động. Điều này sẽ giảm thiểu rủi ro cho việc chọn ngẫu nhiên một thread trong hàng đợi.

 

 

Leave a comment