| |
"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;
}
|
|