HomeDigital EditionSys-Con RadioSearch Java Cd
Advanced Java AWT Book Reviews/Excerpts Client Server Corba Editorials Embedded Java Enterprise Java IDE's Industry Watch Integration Interviews Java Applet Java & Databases Java & Web Services Java Fundamentals Java Native Interface Java Servlets Java Beans J2ME Libraries .NET Object Orientation Observations/IMHO Product Reviews Scalability & Performance Security Server Side Source Code Straight Talking Swing Threads Using Java with others Wireless XML
 

"Embedding The JAVA Virtual Machine, Once And For All"
Vol. 9, Issue 8, p. 14

	



Listing 1: The traditional way to launch a JVM 

typedef jint (JNICALL *pfnCreateJVM)(JavaVM** ppJvm, void** ppEnv, void* args);
// global jvm, may be used by other threads
JavaVM* jvm;	
... ... // other stuff
// Java VM launcher thread, maybe main thread, maybe not
JavaVMInitArgs vm_args;
JavaVMOption options[n]; 
... ... // fill in options
... ... // fill in vm_args
// get JNI_CreateVM address
HMODULE hModule = ::LoadLibrary(your_libpath);
pfnCreateJVM pfn = (pfnCreateJVM)::GetProcAddress(hModule, "JNI_CreateJavaVM");
JNIEnv* env;
// launch jvm
pfn(&jvm, (void**)&env, &vm_args);
// work with env
... ... 
// destroy jvm 
jvm->DestroyJavaVM (); 
jvm = 0;
::FreeLibrary(hModule);

// Java VM consumer thread: thread-1
void thread_fun() {
JNIEnv* env = 0;
// get env
    jvm->AttachCurrentThread(&env, JNI_VERSION_1_2); 
    ... ... // work with env
    jvm->DetachCurrentThread();
}


Listing 2: Thin JVM wrapper

class CJavaVM { // JavaVM* wrapper
private:
    static JavaVM* jvm;
public:
    static bool StartJavaVM(std::string jvmpath, JavaVMInitArgs& args);
    static bool DestroyJavaVM();
    static bool GetEnv(JNIEnv** ppEnv, jint version);
    static bool AttachCurrentThread(JNIEnv** ppEnv, void* args);
    static bool DetachCurrentThread();
    static bool AttachCurrentThreadAsDaemon(JNIEnv** ppEnv, void* args);
    ... ... // other methods
};
  


Listing 3: Loki::SingletonHolder class template

template < 
           typename T, 
           template <class> class CreationPolicy = CreateUsingNew,
           template <class> class LifetimePolicy = DefaultLifetime,
           template <class> class ThreadingModel = SingleThreaded
         >
class SingletonHolder {
public:
    static T& Instance();
private:
    static void MakeInstance();
    static void DestroySingleton();
    
    typedef typename ThreadingModel<T*>::VolatileType PtrInstanceType;
    static PtrInstanceType pInstance_;
    static bool destroyed_;
};

Listing 4: CJavaVM2 with Loki::SingletonHolder

// CJavaVM2.hpp
class CJavaVM2 { // JavaVM* wrapper
private:
    JavaVM* jvm;
    friend Loki::CreateUsingNew<CJavaVM2>;
    CJavaVM2();
public:
    bool StartJavaVM(std::string jvmpath, JavaVMInitArgs& args);
    bool DestroyJavaVM();
    bool GetEnv(JNIEnv** ppEnv, jint version);
    bool AttachCurrentThread(JNIEnv** ppEnv, void* args);
    bool DetachCurrentThread();
    bool AttachCurrentThreadAsDaemon(JNIEnv** ppEnv, void* args);
    ... ... // other methods
};

// main.cpp 
typedef Loki::SingletonHolder<CJavaVM2> JVM;
int main(){
    JavaVMInitArgs args;
    std::string libpath;
    JNIEnv* env;
    ...... // fill in libpath and args
    CJavaVM2& jvm = JVM::Instance();
    jvm.StartJavaVM(libpath, args);
    jvm.GetEnv(&env, JNI_VERSION_1_2);
    ...... // working with env
    jvm.DestroyJavaVM();    
}

Listing 5: CJavaVM3

template <class JavaVMLauncher>

class CJavaVM3 {
private:
    JavaVM* jvm;

    CJavaVM3 () { JavaVMLauncher::LaunchJavaVM(... /* to do */); }
    ~ CJavaVM3 () { JavaVMLauncher::DestroyJavaVM(... /* to do */); }
    
public:
    bool AttachCurrentThread(JNIEnv** ppEnv, void* args);
    bool GetEnv(JNIEnv** ppEnv, jint version);
    bool AttachCurrentThread(JNIEnv** ppEnv, void* args);
    bool DetachCurrentThread();
    bool AttachCurrentThreadAsDaemon(JNIEnv** ppEnv, void* args);
    ... ... // other methods
};

Listing 6: JVM invocation with CJavaVM3

// main.cpp
typedef CJavaVM3<YourLauncher> CJavaVM;
typedef Loki::SingletonHolder<CJavaVM> JVM;
int main(){
    JNIEnv* env;
    CJavaVM2& jvm = JVM::Instance();
    jvm.GetEnv(&env, JNI_VERSION_1_2);
    ...... // working with env
}

Listing 7:  JTL Threading model

template <class Host>
class SingleThreadModel {
public:    
    typedef Host volatile_type;
    
    typedef boostex::faked_mutex mutex;
    typedef boostex::faked_mutex::scoped_lock scoped_lock;
};

template <class Host>
class MultipleThreadModel {
public:
    typedef volatile Host volatile_type;
    
    typedef boost::mutex mutex;
    typedef boost::mutex::scoped_lock scoped_lock;
};

Listing 8: thread_env_ptr

template < ... >
class thread_env_ptr : public env_ptr_base {
public:
    //... typedefs for SingletonJVM;
public:
    thread_env_ptr() {
        bool bOk = SingletonJVM::Instance().AttachCurrentThread(&env_, 0);            
        if(bOk) {
            if(0 == s_counterptr.get()) {
                s_counterptr.reset(new int(1));
            }else {
                ++(*s_counterptr);
            }                
        }            
    }
    ~thread_env_ptr() {
        if(env_) {
            env_ = 0;
            --(*s_counterptr);
            if(0 == *s_counterptr) {
                SingletonJVM::Instance().DetachCurrentThread();
            }
        }
    }
private:
    static boost::thread_specific_ptr<int> s_counterptr;
};

Listing 9: A complete JTL JVM invocation example

// all necessary headers
typedef jtl::win::DefaultJavaVMLauncher JVMLauncher;
boost::mutex io_mutex; // synchronize std out

class Dummy {
public:
    jtl::thread_env_ptr<JVMLauncher> env_;  
    void Test() {
        boostex::ThreadID::ThreadIdType tid = 
		boostex::ThreadID::get_current_threadid();
        boost::mutex::scoped_lock lock(io_mutex);
        if(env_)
            std::cout << "get JNIEnv* in thread:" 
                      << tid << std::endl;
        else
            std::cout << "can not get JNIEnv* in thread:" 
                      << tid << std::endl;
    }
};

void launch() // thread function
{
    Dummy dummy[3];
    for(int i = 0; i < 3; ++i)
    {
        dummy[i].Test();
    }
}

int main()
{
    boost::thread thrd(&launch);
    
    Dummy dummy;
dummy.Test();

    thrd.join();
    
    return 0;
}
  

 

All Rights Reserved
Copyright ©  2004 SYS-CON Media, Inc.
  E-mail: [email protected]

Java and Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the United States and other countries. SYS-CON Publications, Inc. is independent of Sun Microsystems, Inc.