JUC多并发编程 初探
实现一个简单的线程:
public class TreadDemo {public static void main(String[] args) {Thread thread = new Thread(()->{}, "th");thread.start();}
}
进入 start 方法:
public synchronized void start() {if (threadStatus != 0)throw new IllegalThreadStateException();group.add(this);boolean started = false;try {start0();started = true;} finally {try {if (!started) {group.threadStartFailed(this);}} catch (Throwable ignore) {/* do nothing. If start0 threw a Throwable thenit will be passed up the call stack */}}}private native void start0();
Thread.c :
java 线程是通过 start 的方法启动执行的,主要内容在 native 方法 start0中, openjdk的写 JNI 一般是一一对应的, Thread.java 对应的就是 Thread.c, start0 起始就是 JVM_StartThread。 此时查看源代码可以看到在 jvm.h 中找到了声明,jvm.cpp 中有实现
// Thread.c
static JNINativeMethod methods[] = {{"start0", "()V", (void *)&JVM_StartThread},{"stop0", "(" OBJ ")V", (void *)&JVM_StopThread},{"isAlive", "()Z", (void *)&JVM_IsThreadAlive},{"suspend0", "()V", (void *)&JVM_SuspendThread},{"resume0", "()V", (void *)&JVM_ResumeThread},{"setPriority0", "(I)V", (void *)&JVM_SetThreadPriority},{"yield", "()V", (void *)&JVM_Yield},{"sleep", "(J)V", (void *)&JVM_Sleep},{"currentThread", "()" THD, (void *)&JVM_CurrentThread},{"countStackFrames", "()I", (void *)&JVM_CountStackFrames},{"interrupt0", "()V", (void *)&JVM_Interrupt},{"isInterrupted", "(Z)Z", (void *)&JVM_IsInterrupted},{"holdsLock", "(" OBJ ")Z", (void *)&JVM_HoldsLock},{"getThreads", "()[" THD, (void *)&JVM_GetAllThreads},{"dumpThreads", "([" THD ")[[" STE, (void *)&JVM_DumpThreads},{"setNativeName", "(" STR ")V", (void *)&JVM_SetNativeThreadName},
};
// jvm.cpp
JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread))JVMWrapper("JVM_StartThread");JavaThread *native_thread = NULL;// We cannot hold the Threads_lock when we throw an exception,// due to rank ordering issues. Example: we might need to grab the// Heap_lock while we construct the exception.bool throw_illegal_thread_state = false;// We must release the Threads_lock before we can post a jvmti event// in Thread::start.{// Ensure that the C++ Thread and OSThread structures aren't freed before// we operate.MutexLocker mu(Threads_lock);// Since JDK 5 the java.lang.Thread threadStatus is used to prevent// re-starting an already started thread, so we should usually find// that the JavaThread is null. However for a JNI attached thread// there is a small window between the Thread object being created// (with its JavaThread set) and the update to its threadStatus, so we// have to check for thisif (java_lang_Thread::thread(JNIHandles::resolve_non_null(jthread)) != NULL) {throw_illegal_thread_state = true;} else {// We could also check the stillborn flag to see if this thread was already stopped, but// for historical reasons we let the thread detect that itself when it starts runningjlong size =java_lang_Thread::stackSize(JNIHandles::resolve_non_null(jthread));// Allocate the C++ Thread structure and create the native thread. The// stack size retrieved from java is signed, but the constructor takes// size_t (an unsigned type), so avoid passing negative values which would// result in really large stacks.size_t sz = size > 0 ? (size_t) size : 0;native_thread = new JavaThread(&thread_entry, sz);// At this point it may be possible that no osthread was created for the// JavaThread due to lack of memory. Check for this situation and throw// an exception if necessary. Eventually we may want to change this so// that we only grab the lock if the thread was created successfully -// then we can also do this check and throw the exception in the// JavaThread constructor.if (native_thread->osthread() != NULL) {// Note: the current thread is not being used within "prepare".native_thread->prepare(jthread);}}}if (throw_illegal_thread_state) {THROW(vmSymbols::java_lang_IllegalThreadStateException());}assert(native_thread != NULL, "Starting null thread?");if (native_thread->osthread() == NULL) {// No one should hold a reference to the 'native_thread'.delete native_thread;if (JvmtiExport::should_post_resource_exhausted()) {JvmtiExport::post_resource_exhausted(JVMTI_RESOURCE_EXHAUSTED_OOM_ERROR | JVMTI_RESOURCE_EXHAUSTED_THREADS,"unable to create new native thread");}THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(),"unable to create new native thread");}Thread::start(native_thread);JVM_END
// Thread.cpp
void Thread::start(Thread* thread) {trace("start", thread);// Start is different from resume in that its safety is guaranteed by context or// being called from a Java method synchronized on the Thread object.if (!DisableStartThread) {if (thread->is_Java_thread()) {// Initialize the thread state to RUNNABLE before starting this thread.// Can not set it after the thread started because we do not know the// exact thread state at that time. It could be in MONITOR_WAIT or// in SLEEPING or some other state.java_lang_Thread::set_thread_status(((JavaThread*)thread)->threadObj(),java_lang_Thread::RUNNABLE);}os::start_thread(thread);}
}
基本概念
并发(concurrent):
- 是在同一实体上的多个事件
- 是在同一台处理器上"同时" 处理多个任务
- 同一时刻,其实只有一个事件在发生
并行(parallel):
- 是在不同实体上的多个事件
- 是在多台处理器上同时处理多个任务
- 同一时刻, 大家真的都在做事情,你做你的,我做我的
进程:
在系统中运行的一个应用程序就是一个进程,每一个进程都是它自己的内存空间和系统资源
线程:
轻量级进程,在同一个进程内会有1个活多个线程,是大多数操作系统进行时序调度的基本单元
管程:
- Monitor 其实是一种同步机制,他的义务是保证(同一时间) 只有一个线程可以访问被保护的数据和代码。
- JVM 中同步都是基于进入和推出监视器对象(Monitor, 管程对象)来实现的,每个对象实例都会有一个 Monitor 对象。
- Monitor 对象会与 Java 对象一同创建并销毁,它底层是由 C++ 语言来实现的。
public class TreadDemo {public static void main(String[] args) {Object o = new Object();Thread thread = new Thread(()->{synchronized (o) {}}, "th2");thread.start();}
}
用户线程(User Thread):
- 默认都是用户线程
- 是系统的工作线程,它会完成这个程序需要完成的业务操作
守护线程(Daemon Thread):
- 是一种特殊的线程为其他线程服务的,在后台默默地完成一些系统性的服务 比如垃圾回收线程
- 守护线程作为一个服务线程,没有服务对象就没有必要继续运行了,如果用户线程全部结束了,意味着程序需要完成的业务操作已经结束了,系统可以推出了。所以加入当系统只剩下守护线程的时候,java 虚拟机会自动退出。
守护和用户代码演示:
import java.util.concurrent.TimeUnit;public class DaemonDemo {public static void main(String[] args) {Thread t1 = new Thread(()->{System.out.println(Thread.currentThread().getName() + "\\t 开始运行, " + (Thread.currentThread().isDaemon() ? "守护线程": "用户线程"));for (;;);}, "t1");// 需要在 start 之前,否则会报 IllegalThreadStateExceptiont1.setDaemon(true);t1.start(); try{TimeUnit.SECONDS.sleep(3);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName() + "\\t -- end 主线程");}
}