Đa luồng trong java – Java Multithreading (Bài 7 )

Đa luồng trong java sẽ đề cập đến hai khái niệm Multitasking Multithreading

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, Google Chrome, …

Multithreading: Là khả năng thực hiện đồng thời nhiều phần khác nhau của một chương trình được gọi là thread. Ví dụ trong Microsoft Excel chúng ta có thể làm việc đồng thời với các sheet khác nhau

Đa luồng trong java – Thread ?

Thread là đơn vị nhỏ nhất của mã thực thi mà đoạn mã đó thực hiện một nhiệm vụ cụ thể.

Một ứng dụng có thể được chia nhỏ thành nhiều nhiệm vụ và mỗi nhiệm vụ có thể được giao cho một thread.

Nhiều thread cùng thực hiện đồng thời được gọi là đa luồng (multithread). Các quá trình đang chạy dường như là đồng thời, nhưng thực ra nó không phải là như vậy.

Đa luồng trong java – Vòng đời của một thread

da luong trong java 1Đa luồng trong java – Các trạng thái của thread

da luong trong java 2da luong trong java 3da luong trong java 4Đa luồng trong java – Khởi tạo thread

Hệ thống xử lý đa luồng trong Java được xây dựng trên class Thread và interface Runnable trong packaged java.lang.

da luong trong java 5Cách 1: Tạo thread bằng cách sử dụng interface Runnable

  1. Viết 1 class thực thi interface Runnable và viết lại phương thức  public void run()
  2. Tạo ra 1 object vừa thực thi interface Runnable.
  3. Tạo ra 1 object của class Thread với tham số truyền vào là object thực thi interface Runable.
  4. Gọi phương thức start() để chạy thread

Ví dụ tạo thread bằng cách sử dụng interface Runnable

package thread;

/**
 *
 * @author giasutinhoc.vn
 */
public class FirstThread implements Runnable{

    @Override
    public void run() {
        for (int i = 1; i <= 5; i++) {
            System.out.println("Thong diep tu thread dau tien: " + i);
            try {                
                Thread.sleep(1000);
            } catch (InterruptedException ie) {
                System.err.println(ie.toString());
            }
        }
    }    
}
package thread;

/**
 *
 * @author giasutinhoc.vn
 */
public class SecondThread implements Runnable{

    @Override
    public void run() {
        for (int i = 1; i <= 5; i++) {
            System.out.println("Thong diep tu thread thu hai: " + i);
            try {                
                Thread.sleep(1000);
            } catch (InterruptedException ie) {
                System.err.println(ie.toString());
            }
        }
    }    
}
package thread;

/**
 *
 * @author giasutinhoc.vn
 */
public class ThreadDemo {
    public static void main(String[] args) {
        //Tao doi tuong
        FirstThread ft = new FirstThread();
        SecondThread st = new SecondThread();
        
        //Bat dau thread thu nhat
        Thread t1 = new Thread(ft);
        t1.start();
        
        //Bat dau thread thu hai
        Thread t2 = new Thread(st);
        t2.start();
        
    }
}

Khi chạy chương trình trên, chúng ta sẽ nhận được kết quả sau

da luong trong java 6Cách 2: Tạo thread bằng cách kế thừa từ lớp Thread

  1. Tạo một lớp kế thừa từ lớp Thread và viết lại (override) phương thức run()
  2. Tạo ra một đối tượng của lớp vừa kế thừa từ lớp Thread
  3. Gọi phương thức start() để chạy thread

Ví dụ tạo thread bằng cách kế thừa từ lớp Thread

package thread;

/**
 *
 * @author giasutinhoc.vn
 */
public class ThreeThread extends Thread{

    public ThreeThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 1; i <= 5; i++) {
            System.out.println(i + " " + getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException ie) {
                System.err.println(ie.toString());
            }
        }
        System.out.println(getName() + " da hoan thanh!");
    }
    
    public static void main(String[] args) {
        ThreeThread tt1 = new ThreeThread("Tp. Ho Chi Minh");
        ThreeThread tt2 = new ThreeThread("Tp. Can Tho");
        tt1.start();
        tt2.start();
    }
}

Khi chạy chương trình trên, chúng ta sẽ nhận được kết quả sau

Ví dụ thực hiện 1 công việc bằng nhiều Thread

 package thread;

/**
 *
 * @author giasutinhoc.vn
 */
public class OneTaskUsingMultiThread implements Runnable{

    @Override
    public void run() {
        System.out.println("Xu ly mot tac vu su dung nhieu thread");
    }
    
    public static void main(String[] args) {        
        Thread t1 = new Thread(new OneTaskUsingMultiThread());
        Thread t2 = new Thread(new OneTaskUsingMultiThread());
        t1.start();
        t2.start();
    }
}

Ngoài ra, chúng ta có thể sử dụng cách kế thừa từ class Thread để thực hiện yêu cầu này

Ví dụ thực hiện nhiều công việc sử dụng nhiều Thread

package thread;

/**
 *
 * @author giasutinhoc.vn
 */
public class MultiTaskUsingMultiThread1 extends Thread{

    @Override
    public void run() {
        System.out.println("Task 1");
    }
    
}
package thread;

/**
 *
 * @author giasutinhoc.vn
 */
public class MultiTaskUsingMultiThread2 extends Thread{
    
    @Override
    public void run() {
        System.out.println("Task 2");
    }
}
package thread;

/**
 *
 * @author giasutinhoc.vn
 */
public class MultiTaskUsingMultiThreadDemo {
    public static void main(String[] args) {
        MultiTaskUsingMultiThread1 task1 = new MultiTaskUsingMultiThread1();
        MultiTaskUsingMultiThread2 task2 = new MultiTaskUsingMultiThread2();
        task1.start();
        task2.start();
    }
}

Sự khác nhau giữa cài đặt Runnable và kế thừa Thread

package thread;

/**
 *
 * @author giasutinhoc.vn
 */
public class UsingThread extends Thread{
    private int cnt = 0;

    @Override
    public void run() {
        cnt++;
        System.out.println("Tao thread su dung tu khoa extends: " + cnt);
    }    
}
package thread;

/**
 *
 * @author giasutinhoc.vn
 */
public class UsingRunnable implements Runnable {

    private int cnt = 0;

    @Override
    public void run() {
        cnt++;
        System.out.println("Tao thread su dung tu khoa implements: " + cnt);
    }

}
package thread;

/**
 *
 * @author giasutinhoc.vn
 */
public class DifferenceBetweenDemo {
    public static void main(String[] args) throws InterruptedException {
        //Nhiều đối tượng thread
        UsingRunnable ur = new UsingRunnable();
        Thread t1 = new Thread(ur);
        t1.start();
        Thread.sleep(1000);
        Thread t2 = new Thread(ur);
        t2.start();
        Thread.sleep(1000);
        
        //Mỗi thread tương ứng với một thể hiện
        UsingThread ut1 = new UsingThread();
        ut1.start();
        Thread.sleep(1000);
        UsingThread ut2 = new UsingThread();
        ut2.start();        
    }
}

Khi chạy chương trình trên, chúng ta sẽ nhận được kết quả sau

da luong trong java 8Đa luồng trong java – Quản lý thread

Thứ tự ưu tiên giữa các thread

da luong trong java 9Phương thức join(): Thiết lập một thread phải chờ cho đến khi một thread khác hoạt động xong

package thread;

import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author giasutinhoc.vn
 */
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(500);
            } catch (InterruptedException ie) {
                System.out.println(ie.toString());
            }
        }
        System.out.println();
    }    
    
    public static void main(String[] args) {
        UsingJoinMethod t1 = new UsingJoinMethod("Thread 1");
        UsingJoinMethod t2 = new UsingJoinMethod("Thread 2");
        t1.start();
        try {
            t1.join();
        } catch (InterruptedException ie) {
            System.err.println(ie.toString());
        }
        t2.start();
    }
}

Khi chạy chương trình trên, chúng ta sẽ nhận được kết quả sau

da luong trong java 10Đồng bộ hóa giữa các thread

Đồng bộ hóa chính là việc sắp xếp thứ tự các luồng khi truy xuất vào cùng đối tượng sao cho không có sự xung đột dữ liệu.

Để đảm bảo rằng một nguồn tài nguyên chia sẻ được sử dụng bởi một thread tại một thời điểm, chúng ta sử dụng đồng bộ hóa (synchronization).

Mối quan hệ giữa các thead

Java cũng cung cấp cơ chế giao tiếp liên-quá trình bằng cách sử dụng phương thức wait(), notify() notifyAll().

Các phương thức  wait(), notify() and notifyAll() chỉ được gọi từ bên trong một phương thức được đồng bộ hóa (synchronized method).

da luong trong java 11Ví dụ về mối quan hệ giữa các thread

package thread.relationship;

/**
 *
 * @author giasutinhoc.vn
 */
public class Customer {
    private int balance = 1000;
    
    public Customer() {
        System.out.println("Tai khoan cua ban la " + balance);
    }
    
    private synchronized void withdraw(int amount) {
        System.out.println("Giao dich rut tien dang thuc hien " + amount + "...");
        if(balance < amount) {
            System.out.println("Cannot withdraw!");
            try {
                wait();
            } catch (InterruptedException ie) {
                System.out.println(ie.toString());
            }
        }
        balance -= amount;
        System.out.println("Rut tien thanh cong. Tai khoan hien tai cua ban la " + balance);
    }
    
    private synchronized void deposit(int amount) {
        System.out.println("Giao dich nap tien " + amount + "...");
        balance += amount;
        System.out.println("Nap tien thanh cong. Tai khoan hien tai cua ban la " + balance);
        notify();
    }
    
    public static void main(String[] args) {
        Customer c = new Customer();
        Thread t1 = new Thread(){
            public void run() {
                c.withdraw(2000);
            }
        };
        t1.start();
        
        Thread t2 = new Thread(){
            public void run() {
                c.deposit(3000);
            }
        };
        t2.start();
    }
}

Khi chạy chương trình trên, chúng ta sẽ nhận được kết quả sau

Đa luồng trong java – Tổng kết

  • Khái niệm multitasking và multithreading
  • Khái niệm ‘thread’ – luồng
  • Các trạng thái của thread
  • Khởi tạo thread
  • Quản lý thread

Xem giáo trình môn lập trình java

Trả lời