Xem thêm

Hướng dẫn Java Design Pattern – Object Pool

Huy Erick
Bài viết này sẽ giới thiệu về một design pattern quan trọng trong Java - Object Pool Pattern. Đây là một trong những Creational pattern giúp tái sử dụng các đối tượng thay vì tiến...

Bài viết này sẽ giới thiệu về một design pattern quan trọng trong Java - Object Pool Pattern. Đây là một trong những Creational pattern giúp tái sử dụng các đối tượng thay vì tiến hành khởi tạo không kiểm soát.

Object Pool Pattern là gì?

Object Pool Pattern cung cấp một kỹ thuật để quản lý và tái sử dụng các đối tượng trong chương trình. Thay vì tạo ra một đối tượng mới khi cần sử dụng, chúng ta chỉ cần lấy một đối tượng đã có sẵn từ object pool. Sau khi sử dụng, đối tượng sẽ được trả về pool để tái sử dụng cho các client khác.

Ý tưởng của Object Pool Pattern được thể hiện như sau: chúng ta sử dụng một object pool để quản lý một tập hợp các đối tượng. Khi client cần sử dụng đối tượng, thay vì tạo mới, client chỉ cần yêu cầu lấy một đối tượng đã có sẵn trong pool. Nếu tất cả các đối tượng trong pool đều đang được sử dụng, client phải chờ đến khi có đối tượng trả về pool.

Với Object Pool Pattern, chúng ta có thể giảm thiểu lãng phí tài nguyên do việc khởi tạo đối tượng mới lặp lại. Đồng thời, cũng nâng cao performance của chương trình.

Cài đặt Object Pool Pattern trong Java

Để cài đặt Object Pool Pattern trong Java, chúng ta cần xây dựng ba thành phần cơ bản sau:

Client

Client là class yêu cầu khởi tạo đối tượng để sử dụng.

PooledObject

PooledObject là class mà việc khởi tạo tốn nhiều thời gian và có chi phí cao. Đối với một ứng dụng, chúng ta cần giới hạn số lượng đối tượng được khởi tạo.

ObjectPool

ObjectPool là thành phần quan trọng nhất trong Object Pool Pattern. Đây là lớp quản lý danh sách các PooledObject đã được khởi tạo và đang được sử dụng. Lớp ObjectPool cung cấp các phương thức để lấy đối tượng từ pool và trả đối tượng sau khi sử dụng về pool.

Dưới đây là đoạn code minh họa cho việc cài đặt Object Pool Pattern trong Java:

// Code minh họa
package com.gpcoder.patterns.creational.objecpool.taxi;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;

public class TaxiPool {
    private static final long EXPIRED_TIME_IN_MILISECOND = 1200; // 1.2s
    private static final int NUMBER_OF_TAXI = 4;

    private final List available = Collections.synchronizedList(new ArrayList<>());
    private final List inUse = Collections.synchronizedList(new ArrayList<>());
    private final AtomicInteger count = new AtomicInteger(0);
    private final AtomicBoolean waiting = new AtomicBoolean(false);

    public synchronized Taxi getTaxi() {
        if (!available.isEmpty()) {
            Taxi taxi = available.remove(0);
            inUse.add(taxi);
            return taxi;
        }

        if (count.get() == NUMBER_OF_TAXI) {
            this.waitingUntilTaxiAvailable();
            return this.getTaxi();
        }

        Taxi taxi = this.createTaxi();
        inUse.add(taxi);
        return taxi;
    }

    public synchronized void release(Taxi taxi) {
        inUse.remove(taxi);
        available.add(taxi);
        System.out.println(taxi.getName() + " is free");
    }

    private Taxi createTaxi() {
        waiting(200); // Thời gian để tạo một chiếc taxi
        Taxi taxi = new Taxi("Taxi " + count.incrementAndGet());
        System.out.println(taxi.getName() + " is created");
        return taxi;
    }

    private void waitingUntilTaxiAvailable() {
        if (waiting.get()) {
            waiting.set(false);
            throw new TaxiNotFoundException("No taxi available");
        }

        waiting.set(true);
        waiting(EXPIRED_TIME_IN_MILISECOND);
    }

    private void waiting(long numberOfSecond) {
        try {
            TimeUnit.MILLISECONDS.sleep(numberOfSecond);
        } catch (InterruptedException e) {
            e.printStackTrace();
            Thread.currentThread().interrupt();
        }
    }
}

Trong ví dụ trên, chúng ta sử dụng TaxiPool để quản lý 4 chiếc taxi. Mỗi chiếc taxi mất 200ms để đến điểm đón khách và chở khách trong khoảng thời gian từ 1000ms đến 1500ms. Nếu khách hàng chờ quá 1200ms mà không có taxi sẵn sàng, khách hàng sẽ hủy.

Với Object Pool Pattern, chúng ta có thể tối ưu hóa việc sử dụng tài nguyên và nâng cao hiệu suất của chương trình.

Con đường sử dụng Java Design Pattern còn rất dài và thú vị. Hy vọng rằng bài viết này đã cung cấp cho bạn kiến thức cần thiết để khám phá thêm về Object Pool Pattern trong Java.

1