Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Java-关于对象池的创建问题和多线程调用对象池对象发生阻塞的测试 #1

Open
jeffrey1995 opened this issue Jun 12, 2016 · 0 comments

Comments

@jeffrey1995
Copy link
Owner

关于对象池,形象地说就是事先创建好了一些某类型的对象放在对象池中。当程序(线程)需要使用这种对象的时候,直接从对象池中获取该对象。

然而也有很多问题需要注意,一些不容忽视的问题就是:

1.原子操作的问题,共享资源区是不能同时访问的,所以使用synchronized来并发防止访问错误。

2.线程阻塞问题,当对象池中对象全部在使用中,已经没有空闲对象,然而此时又有一个线程向对象池申请对象,那么该线程将会陷入阻塞状态,所谓阻塞就是让线程进入有限等待中,不断的检查对象池中是否有空闲对象,若此时有对象在使用完之后被释放,那么该等待程序将从等待中跳出,成功获取空闲对象。

用Java语言实现方法:

1.首先创建一个对象池ObjectPool类:

package com.work_09;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Enumeration;
import java.util.Vector;

class ObjectPool {
private int numObjects = 3; // 对象池的大小
private int maxObjects = 6; // 对象池最大的大小
private Vector objects = null;
private Class<?> clazz = null;
public ObjectPool(Class cla){
clazz = cla;
}

/*** 创建一个对象池 
 * @throws SecurityException 
 * @throws NoSuchMethodException 
 * @throws InvocationTargetException 
 * @throws IllegalArgumentException 
 * @throws IllegalAccessException 
 * @throws InstantiationException ***/
@SuppressWarnings("unchecked")
public synchronized void createPool() throws Exception{     
    Constructor<?> con = clazz.getDeclaredConstructor();    
    // 确保对象池没有创建。如果创建了,保存对象的向量 objects 不会为空     
    if (objects != null) {     
        return; // 如果己经创建,则返回     
    }     

    // 创建保存对象的向量 , 初始时有 0 个元素     
    objects = new Vector();    

    //根据 numObjects 中设置的值,循环创建指定数目的对象     
    for(int i=0;i<this.numObjects;i++)
    {
            System.out.println("P创建了一个对象");
            T obj = (T) con.newInstance();
            objects.addElement(new PooledObject(obj));
    }
}
public synchronized void createObjects() throws Exception, SecurityException
{
    Constructor<?> con = clazz.getDeclaredConstructor(); 
    for(int i=0;i<this.numObjects;i++)
    {
        if(this.objects.size() < maxObjects)
            {
            System.out.println("C创建了一个对象");
            T obj = (T) con.newInstance();
            objects.addElement(new PooledObject(obj));
            }
    }
}


public synchronized T getObject() throws Exception
{
    // 确保对象池己被创建     
    if (objects == null) {     
        return null; // 对象池还没创建,则返回 null     
    }     

    T conn = getFreeObject(); // 获得一个可用的对象     

    // 如果目前没有可以使用的对象,即所有的对象都在使用中     
    while (conn == null) {     
        wait(250);     
        conn = getFreeObject(); // 重新再试,直到获得可用的对象,如果     
        // getFreeObject() 返回的为 null,则表明创建一批对象后也不可获得可用对象     
    }     
    System.out.println("成功    获取     对象!!!");
    return conn;// 返回获得的可用的对象     
}

 private T getFreeObject() throws Exception{     

     T obj = findFreeObject();     

        if (obj == null) {     
            createObjects();     //如果目前对象池中没有可用的对象,创建一些对象     

            // 重新从池中查找是否有可用对象     
            obj = findFreeObject();     

           // 如果创建对象后仍获得不到可用的对象,则返回 null     
            if (obj == null) {     
                return null;     
            }     
        }     

        return obj;     
 }     

 private T findFreeObject()
 {     

        T obj = null;     
        PooledObject<T> pObj = null;     

        // 获得对象池向量中所有的对象     
        Enumeration enumerate = objects.elements();     

        // 遍历所有的对象,看是否有可用的对象     
        while (enumerate.hasMoreElements()) 
        {     
            pObj = (PooledObject) enumerate.nextElement();     

           // 如果此对象不忙,则获得它的对象并把它设为忙     
            if (!pObj.isBusy()) 
            {     
                obj = pObj.getObject();     
                pObj.setBusy(true);
                return obj;
            }       
        }

        return obj;// 返回找到到的可用对象  
 }

 public void returnObject(T obj) {     

        // 确保对象池存在,如果对象没有创建(不存在),直接返回     
        if (objects == null) {     
            return;     
        }     

        PooledObject<T> pObj = null;     

        Enumeration enumerate = objects.elements();     

        // 遍历对象池中的所有对象,找到这个要返回的对象对象     
        while (enumerate.hasMoreElements()) {     
            pObj = (PooledObject) enumerate.nextElement();     

            // 先找到对象池中的要返回的对象对象     
            if (obj == pObj.getObject()) {     
                // 找到了 , 设置此对象为空闲状态
                System.out.println("成功   释放    对象~~~");
                pObj.setBusy(false);                    
                break;     
            }     
        }     
    }     

 public synchronized void closeObjectPool() {     

        // 确保对象池存在,如果不存在,返回     
        if (objects == null) {     
            return;     
        }     

        PooledObject<T> pObj = null;     

        Enumeration enumerate = objects.elements();     

        while (enumerate.hasMoreElements()) {     

            pObj = (PooledObject) enumerate.nextElement();     

            // 如果忙,等 5 秒     
            if (pObj.isBusy()) {     
                wait(5000); // 等 5 秒     
            }     

            // 从对象池向量中删除它     
            objects.removeElement(pObj);     
        }     

        // 置对象池为空     
        objects = null;     
    }
 private void wait(int mSeconds) {     
        try {     
            Thread.sleep(mSeconds);     
        }
       catch (InterruptedException e) {     
        }     
    }     

}

2.这里还有一个PooledObject类,它用来封装对象池中的对象,主要添加了一个busy参数,来标志对象的使用状态:

package com.work_09;

class PooledObject{

T objection = null;// 对象     
boolean busy = false; // 对象是否正在使用的标志,默认没有正在使用     

// 构造函数,根据一个 Object 构告一个 PooledObject 对象     
public PooledObject(T objection) {     

    this.objection = objection;     

}     

// 返回此对象中的对象     
public T getObject() {     
    return objection;     
}     

// 设置此对象的,对象     
public void setObject(T objection) {     
    this.objection = objection;     

}     

// 获得对象对象是否忙     
public boolean isBusy() {     
    return busy;     
}     

// 设置对象的对象正在忙     
public void setBusy(boolean busy) {     
    this.busy = busy;     
}     

}

3.测试程序Pool_Test:

package com.work_09;

import com.work_06.Student;

public class Pool_Test implements Runnable {
static ObjectPool objPool = null;
public static void main(String[] args) throws Exception {
objPool = new ObjectPool(Student.class); //创建一个静态池
objPool.createPool(); //创建池,生成最小数目的对象
for(int i=0;i<10;i++){ //十个线程并发访问
Test();
}
}
public static void Test() throws Exception
{
Thread t0 = new Thread(new Pool_Test());
t0.start();
}
public Pool_Test() throws Exception {
// TODO Auto-generated constructor stub

}

@Override
public void run() {
    // TODO Auto-generated method stub
    Student s = null;
    try {
        s = objPool.getObject();           //获取对象
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    try {
        Thread.sleep(3000);                //为了看到阻塞效果,让线程延迟3秒。
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } 
    objPool.returnObject(s);           //释放对象
}

}
4.运行结果:

P创建了一个对象
P创建了一个对象
P创建了一个对象
成功 获取 对象!!!
成功 获取 对象!!!
成功 获取 对象!!!
C创建了一个对象
C创建了一个对象
C创建了一个对象
成功 获取 对象!!!
成功 获取 对象!!!
成功 获取 对象!!!
成功 释放 对象~~~
成功 释放 对象~~~
成功 释放 对象~~~
成功 释放 对象~~~
成功 释放 对象~~~
成功 释放 对象~~~
成功 获取 对象!!!
成功 获取 对象!!!
成功 获取 对象!!!
成功 获取 对象!!!
成功 释放 对象~~~
成功 释放 对象~~~
成功 释放 对象~~~
成功 释放 对象~~~
结果分析:因为对象池起初大小为3,在前三个对象获取到对象后并未释放,第四个线程申请对象时,已没有空闲对象,所以此时在对象池中又创建了一些对象(3个),但是对象数十不能超过最大大小:6的。当第七个以后的线程来申请对象时,就会陷入阻塞状态,(一直循环等待空闲资源),直到前面的线程将资源(对象)释放后,才能获取资源,跳出循环。

     以上纯属博主个人观点,也有很多不足和片面的看法,敬请见谅,也欢迎有同样爱好的小伙伴来与我讨论!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant