Lập Trình Đa Luồng (Multithreading) Demo producer and consumer in Java


 Đa luồng trong java (Multithreading in java)

1. Thread là gì? Multi-thread là gì?
- Thread là một tiến trình đơn vị xử lý 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 là khái niệm cho nhiều tiến trình chạy đồ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: Trong một game đánh nhau có 2 người chơi thì mỗi người chơi sẽ do 1 luồng quản lý. Các hoạt cảnh game có thể do một luồng khác quản lý. Làm cho game trở nên sinh động.

2. Cách tạo luồng trong Java
    Có 2 cách tạo 1 luồng trong Java:
Cách 1: Kế thừa từ Thread
public class MyThread extends Thread {
    public void run(){
       System.out.println("Thread 1 đang chạy");
    }
  }
Chạy Thread:
MyThread myThread = new MyThread();
myTread.start();
Cách 2: Implement Interface Runnable hoặc Callable
public class MyRunnable implements Runnable {
    public void run(){
       System.out.println("Thread Runnable đang chạy");
    }
  }
Chạy Thread Runnable:
Thread thread = new Thread(new MyRunnable());
thread.start();
* Dùng callable trong trường hợp muốn trả về giá trị khi Thread thực hiện xong
public class MyCallable implements Callable<String> {
    public String call(){
       return "Kết quả trả về";
    }
}
* Vậy khi nào dùng cách 2 và khi nào dùng cách 1?
Ở đây 2 cách đều như nhau, nhưng thường dùng cách 2 cho những trường hợp đa kế thừa. Chú ý trong java ta không thể kế thừa 2 class nhưng có thể implement nhiều Interface.

3. Vòng đời của Thread (Life cycle )


* New: Đây là trạng thái khi luồng vừa được khởi tạo bằng phương thức khởi tạo của lớp Thread nhưng chưa được start(). Ở trạng thái này, luồng được tạo ra nhưng chưa được cấp phát tài nguyên và cũng chưa chạy. Nếu luồng đang ở trạng thái này mà ta gọi các phương thức ép buộc stop,resume,suspend … sẽ là nguyên nhân sảy ra ngoại lệ IllegalThreadStateException .

* Runnable: Sau khi gọi phương thức start() thì luồng test đã được cấp phát tài nguyên và các lịch điều phối CPU cho luồng test cũng bắt đầu có hiệu lực. Ở đây, chúng ta dùng trạng thái là Runnable chứ không phải Running, vì như đã nói ở phần đầu (Các mô hình đa luồng) thì luồng không thực sự luôn chạy mà tùy vào hệ thống mà có sự điều phối CPU khác nhau. 

* Running: Luồng đang chạy và CPU có trong lịch trình điều phối của CPU.

* Non-Runnable (Blocked): Luồng đã thực hiện xong nhưng vẫn còn sống. 

* Terminated: Luồng đã chết khi thoát khỏi hàm run()

4. Ưu nhược điểm của đa luồng:
*  Ưu điểm của đa luồng:
- Mỗi luồng có thể dùng chung và chia sẻ nguồn tài nguyên trong quá trình chạy, nhưng có thể thực hiện một cách độc lập.
- Ứng dụng trách nhiệm có thể được tách
+ Luồng chính chạy giao diện người dung
+ Các luồng phụ nhiệm gửi đến luồng chính.
- Luồng mang tính chất trừu tượng
- Một chương trình đa luồng hoạt động nhanh hơn trên máy tính có cấu hình tốt và mạnh
*  Nhược điểm của đa luồng:
- Càng nhiều luồng thì xử lý càng phức tạp
- Cần phát hiện tránh các luồng chết, luồng chạy mà không làm gì trong ứng dụng cả

5. DEMO Ứng Dụng Producer Consumer 

*Mô Hình
        PRODUCER -------->   |||||QUEUE||||| ----------> CONSUMER

- Producer liên tục tạo ra sản phẩm bỏ vào kho (Queue). Nếu kho đầy thì đợi.
- Consumer kiểm tra sản phẩn có trong kho nếu có thì thực hiện lấy sản phẩm ra. Không có thì đợi.

* Producer.java
/**
 *
 * @author HAINN
 */
public class Producer extends Thread{
    private BoundedBufferQueue content; //khai bao kho

    public Producer(BoundedBufferQueue content) {
        this.content = content;
    }

    @Override
    public void run() {
        while(true){
            Random r = new Random();
            int product = (int)(r.nextInt(100));//tao san pham tu 0->99
            content.addProduct(product);              
        }
    }
}

Consumer.java
/**
 *
 * @author HAINN
 */
public class Consumer extends Thread{
    
    private BoundedBufferQueue content; //khai bao kho

    public Consumer(BoundedBufferQueue content) {
        this.content = content;
    }

    @Override
    public void run() {
        while(true){
            int x = content.getProduct(); //lay 1 sp ra khoi kho
            if(x != Integer.MIN_VALUE) 
                System.out.println("Consumer get: " + x); 
        }
    }
   
}

BoundedBufferQueue.java
/**
 *
 * @author HAINN
 */
public class BoundedBufferQueue {
   private int arr[]; // mang luu tru san pham (kho)
   private int max; //size cua mang
   private static int lastPosition = 0;//luu vi tri san pham cuoi cung
   
   /**
    * contractor khoi tao khi new mot BoundedBufferQueue
    */
    public BoundedBufferQueue(int maxN) {
        max = (maxN > 0)? maxN : 100; 
        arr = new int[max];//tao mang max phan tu
    }
   
    //them san pham vao kho
    public synchronized void addProduct(int value){           
        try{                
            if(isFull()){//neu Kho day San pham
                Thread.currentThread().wait();//dung thread add SP  
            } else {                   
                arr[lastPosition] = value; //add sp vao Kho
                lastPosition++; //tang vi tri chua sp len 1         
                System.out.println("Producer add: "+value +" ");
            }
           notifyAll();             
        }catch(Exception e){}
   
    }
    
    //lay san pham
    public synchronized int getProduct(){       
         int result = Integer.MIN_VALUE; //san pham duoc ban        
         try{         
             if(isEmpty())              //neu mang trong                
               Thread.currentThread().wait();  //thread lay SP doi          
             else if(lastPosition > 0){
                 result = arr[0];  //lay san pham dau tien     
                 for(int i=0; i < lastPosition - 1; i++)          
                        arr[i] = arr[i+1]; //day cac sp phia sau len truoc  
                 lastPosition--;  
             }             
           notifyAll();                
        }catch(Exception e){}         
        return result;
    }
    
    public boolean isFull(){
        return lastPosition == max;
    }
    
    public boolean isEmpty(){
        return lastPosition == 0;
    }

    public static int getLastPosition() {
        return lastPosition;
    }

}
Main.java
/**
 *
 * @author HAINN
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        BoundedBufferQueue kho = new BoundedBufferQueue(5);//tao kho 5 SP
        Producer p = new Producer(kho);
        Producer p2 = new Producer(kho);
        Consumer c = new Consumer(kho);
        
        p.start();
        p2.start();
        c.start();
    }
}



SHARE THIS

1 comment:

  1. lập trình đa luồng multithreading với Android
    http://histudycode.com/android/multithreading-lap-trinh-da-luong-trong-android/

    ReplyDelete