1.JAVA如何获取jvm中的线线程所有线程?
2.Java基础:Java虚拟机(JVM)
3.java线程池(一):java线程池基本使用及Executors
4.jvm中一个线程调用sleep(100),然后发生stw(stop-the-world
5.JVM调优-CMS常见参数、线程计算与推荐配置
6.JAVA 线ç¨
JAVA如何获取jvm中的程源所有线程?
在Java中,你可以通过Java的线线程java.lang.management包获取JVM中的所有线程。这个包提供了一些用于管理和监视Java虚拟机的程源工具。具体来说,线线程你可以使用ThreadMXBean接口来获取线程信息。程源通达信macd指标源码
以下是线线程一段示例代码,演示如何获取和打印JVM中的程源所有线程:
java复制代码
import java.lang.management.ManagementFactory;
import java.lang.management.ThreadInfo;
import java.lang.management.ThreadMXBean;
public class Main {
public static void main(String[] args) {
// 获取ThreadMXBean
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
// 不需要获取同步的monitor和synchronizer信息,仅获取线程和线程堆栈信息
ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false,线线程 false);
// 遍历线程信息,仅打印线程ID和线程名称信息
for (ThreadInfo threadInfo : threadInfos) {
System.out.println("[" + threadInfo.getThreadId() + "] " + threadInfo.getThreadName());
}
}
}
这段代码首先通过ManagementFactory.getThreadMXBean()获取ThreadMXBean实例,程源然后调用dumpAllThreads()方法获取所有线程的线线程ThreadInfo,最后遍历并打印所有线程的程源ID和名称。
需要注意的线线程是,dumpAllThreads()方法会返回一个ThreadInfo数组,程源每个ThreadInfo代表一个线程,线线程包含了关于该线程的大量信息,包括线程ID、线程名称、线程状态、线程堆栈信息等。在上面的示例代码中,我们只打印了线程ID和线程名称,但你可以根据需要打印其他信息。
Java基础:Java虚拟机(JVM)
JVM是Java Virtual Machine的缩写,它是一种基于计算设备的规范,提供虚拟机功能,屏蔽了操作系统平台信息,webrt源码实现Java语言在不同平台运行时的平台无关性。通过JVM,Java实现一次编译多处运行。
Java运行环境(JRE)是JVM的运行平台,包括虚拟机平台和虚拟机本体(JVM)。Java开发工具包(JDK)则为Java的开发提供工具,依赖于JRE,通常JDK安装会附带一个JRE。
JVM结构包括:程序计数器、Java堆、Java虚拟机栈、本地方法栈、方法区。程序计数器用于指示代码执行位置,每个线程有独立内存区域。Java虚拟机栈和本地方法栈与线程生命周期相同,用于方法执行的内存模型和本地方法服务。Java堆是共享区域,用于存放对象实例,垃圾回收的主要区域。方法区用于存储已加载类信息、常量、静态变量、编译后代码,非堆区,可能存在内存回收。superwebsocket源码代码缓存用于存储编译后的原生代码。类信息包括运行时常量池和方法数据。
Java垃圾回收通过收集内存中不再使用的对象,减少内存泄漏和程序错误。根据对象的生命周期特征,采用新生代和旧生代的方式进行收集,减少对应用的暂停时间。不同对象引用类型采用不同方法进行回收。
JVM线程与原生线程的关系:JVM允许程序使用多个并发线程,与操作系统原生线程直接映射。Java线程结束时,操作系统线程被回收。操作系统调度所有线程,分配到可用CPU上。线程结束时释放所有资源。
java线程池(一):java线程池基本使用及Executors
@[toc] 在前面学习线程组的时候就提到过线程池。实际上线程组在我们的日常工作中已经不太会用到,但是线程池恰恰相反,是我们日常工作中必不可少的工具之一。现在开始对线程池的使用,以及底层ThreadPoolExecutor的源码进行分析。1.为什么需要线程池我们在前面对线程基础以及线程的生命周期有过详细介绍。一个基本的常识就是,线程是一个特殊的对象,其底层是依赖于JVM的native方法,在jvm虚拟机内部实现的kafkaproducer源码。线程与普通对象不一样的地方在于,除了需要在堆上分配对象之外,还需要给每个线程分配一个线程栈、以及本地方法栈、程序计数器等线程的私有空间。线程的初始化工作相对于线程执行的大多数任务而言,都是一个耗时比较长的工作。这与数据库使用一样。有时候我们连接数据库,仅仅只是为了执行一条很小的sql语句。但是在我们日常的开发工作中,我们的绝大部分工作内容,都会分解为一个个短小的执行任务来执行。这样才能更加合理的复用资源。这种思想就与我们之前提到的协程一样。任务要尽可能的小。但是在java中,任务不可能像协程那样拆分得那么细。那么试想,如果说,有一个已经初始化好的很多线程,在随时待命,那么当我们有任务提交的时候,这些线程就可以立即工作,无缝接管我们的任务请求。那么效率就会大大增加。gnumake源码这些个线程可以处理任何任务。这样一来我们就把实际的任务与线程本身进行了解耦。从而将这些线程实现了复用。 这种复用的一次创建,可以重复使用的池化的线程对象就被成为线程池。 在线程池中,我们的线程是可以复用的,不用每次都创建一个新的线程。减少了创建和销毁线程的时间开销。 同时,线程池还具有队列缓冲策略,拒绝机制和动态线程管理。可以实现线程环境的隔离。当一个线程有问题的时候,也不会对其他的线程造成影响。 以上就是我们使用线程池的原因。一句话来概括就是资源复用,降低开销。
2.java中线程池的实现在java中,线程池的主要接口是Executor和ExecutorService在这两个接口中分别对线程池的行为进行了约束,最主要的是在ExecutorService。之后,线程池的实际实现类是AbstractExecutorService类。这个类有三个主要的实现类,ThreadpoolExecutorService、ForkJoinPool以及DelegatedExecutorService。
后面我们将对这三种最主要的实现类的源码以及实现机制进行分析。
3.创建线程的工厂方法Executors在java中, 已经给我们提供了创建线程池的工厂方法类Executors。通过这个类以静态方法的模式可以为我们创建大多数线程池。Executors提供了5种创建线程池的方式,我们先来看看这个类提供的工厂方法。
3.1 newFixedThreadPool/** * Creates a thread pool that reuses a fixed number of threads * operating off a shared unbounded queue.At any point, at most * { @code nThreads} threads will be active processing tasks. * If additional tasks are submitted when all threads are active, * they will wait in the queue until a thread is available. * If any thread terminates due to a failure during execution * prior to shutdown, a new one will take its place if needed to * execute subsequent tasks.The threads in the pool will exist * until it is explicitly { @link ExecutorService#shutdown shutdown}. * * @param nThreads the number of threads in the pool * @return the newly created thread pool * @throws IllegalArgumentException if { @code nThreads <= 0} */public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());}这个方法能够创建一个固定线程数量的无界队列的线程池。参数nthreads是最多可同时处理的活动的线程数。如果在所有线程都在处理任务的情况下,提交了其他的任务,那么这些任务将处于等待队列中。直到有一个线程可用为止。如果任何线程在关闭之前的执行过程中,由于失败而终止,则需要在执行后续任务的时候,创建一个新的线程来替换。线程池中的所有线程都将一直存在,直到显示的调用了shutdown方法。 上述方法能创建一个固定线程数量的线程池。内部默认的是使用LinkedBlockingQueue。但是需要注意的是,这个LinkedBlockingQueue底层是链表结构,其允许的最大队列长度为Integer.MAX_VALUE。
public LinkedBlockingQueue() { this(Integer.MAX_VALUE);}这样在使用的过程中如果我们没有很好的控制,那么就可能导致内存溢出,出现OOM异常。因此这种方式实际上已经不被提倡。我们在使用的过程中应该谨慎使用。 newFixedThreadPool(int nThreads, ThreadFactory threadFactory)方法:
/** * Creates a thread pool that reuses a fixed number of threads * operating off a shared unbounded queue, using the provided * ThreadFactory to create new threads when needed.At any point, * at most { @code nThreads} threads will be active processing * tasks.If additional tasks are submitted when all threads are * active, they will wait in the queue until a thread is * available.If any thread terminates due to a failure during * execution prior to shutdown, a new one will take its place if * needed to execute subsequent tasks.The threads in the pool will * exist until it is explicitly { @link ExecutorService#shutdown * shutdown}. * * @param nThreads the number of threads in the pool * @param threadFactory the factory to use when creating new threads * @return the newly created thread pool * @throws NullPointerException if threadFactory is null * @throws IllegalArgumentException if { @code nThreads <= 0} */public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) { return new ThreadPoolExecutor(nThreads, nThreads,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(),threadFactory);}这个方法与3.1中newFixedThreadPool(int nThreads)的方法的唯一区别就是,增加了threadFactory参数。在前面方法中,对于线程的创建是采用的默认实现Executors.defaultThreadFactory()。而在此方法中,可以根据需要自行定制。
3.2 newSingleThreadExecutor/** * Creates an Executor that uses a single worker thread operating * off an unbounded queue. (Note however that if this single * thread terminates due to a failure during execution prior to * shutdown, a new one will take its place if needed to execute * subsequent tasks.)Tasks are guaranteed to execute * sequentially, and no more than one task will be active at any * given time. Unlike the otherwise equivalent * { @code newFixedThreadPool(1)} the returned executor is * guaranteed not to be reconfigurable to use additional threads. * * @return the newly created single-threaded Executor */public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));}此方法将会创建指有一个线程和一个无届队列的线程池。需要注意的是,如果这个执行线程在执行过程中由于失败而终止,那么需要在执行后续任务的时候,用一个新的线程来替换。 那么这样一来,上述线程池就能确保任务的顺序性,并且在任何时间都不会有多个线程处于活动状态。与newFixedThreadPool(1)不同的是,使用newSingleThreadExecutor返回的ExecutorService不能被重新分配线程数量。而使用newFixExecutor(1)返回的ExecutorService,其活动的线程的数量可以重新分配。后面专门对这个问题进行详细分析。 newSingleThreadExecutor(ThreadFactory threadFactory) 方法:
/** * Creates an Executor that uses a single worker thread operating * off an unbounded queue, and uses the provided ThreadFactory to * create a new thread when needed. Unlike the otherwise * equivalent { @code newFixedThreadPool(1, threadFactory)} the * returned executor is guaranteed not to be reconfigurable to use * additional threads. * * @param threadFactory the factory to use when creating new * threads * * @return the newly created single-threaded Executor * @throws NullPointerException if threadFactory is null */public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) { return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(),threadFactory));}这个方法与3.3中newSingleThreadExecutor的区别就在于增加了一个threadFactory。可以自定义创建线程的方法。
3.3 newCachedThreadPool/** * Creates a thread pool that creates new threads as needed, but * will reuse previously constructed threads when they are * available.These pools will typically improve the performance * of programs that execute many short-lived asynchronous tasks. * Calls to { @code execute} will reuse previously constructed * threads if available. If no existing thread is available, a new * thread will be created and added to the pool. Threads that have * not been used for sixty seconds are terminated and removed from * the cache. Thus, a pool that remains idle for long enough will * not consume any resources. Note that pools with similar * properties but different details (for example, timeout parameters) * may be created using { @link ThreadPoolExecutor} constructors. * * @return the newly created thread pool */public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE,L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>());}这个方法用来创建一个线程池,该线程池可以根据需要自动增加线程。以前的线程也可以复用。这个线程池通常可以提高很多执行周期短的异步任务的性能。对于execute将重用以前的构造线程。如果没有可用的线程,就创建一个 新的线程添加到pool中。秒内,如果该线程没有被使用,则该线程将会终止,并从缓存中删除。因此,在足够长的时间内,这个线程池不会消耗任何资源。可以使用ThreadPoolExecutor构造函数创建具有类似属性但是详细信息不同的线程池。 ?需要注意的是,这个方法创建的线程池,虽然队列的长度可控,但是线程的数量的范围是Integer.MAX_VALUE。这样的话,如果使用不当,同样存在OOM的风险。比如说,我们使用的每个任务的耗时比较长,任务的请求又非常快,那么这样势必会造成在单位时间内创建了大量的线程。从而造成内存溢出。 newCachedThreadPool(ThreadFactory threadFactory)方法:
/** * Creates a thread pool that creates new threads as needed, but * will reuse previously constructed threads when they are * available, and uses the provided * ThreadFactory to create new threads when needed. * @param threadFactory the factory to use when creating new threads * @return the newly created thread pool * @throws NullPointerException if threadFactory is null */public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) { return new ThreadPoolExecutor(0, Integer.MAX_VALUE,L, TimeUnit.SECONDS,new SynchronousQueue<Runnable>(),threadFactory);}这个方法区别同样也是在于,增加了threadFactory可以自行指定线程的创建方式。
2.4 newScheduledThreadPool/** * Creates a thread pool that can schedule commands to run after a * given delay, or to execute periodically. * @param corePoolSize the number of threads to keep in the pool, * even if they are idle * @return a newly created scheduled thread pool * @throws IllegalArgumentException if { @code corePoolSize < 0} */public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize);}创建一个线程池,该线程池可以将任务在指定的延迟时间之后运行。或者定期运行。这个方法返回的是ScheduledThreadPoolExecutor。这个类是ThreadPoolExecutor的子类。在原有线程池的的基础之上,增加了延迟和定时功能。我们在后面分析了ThreadPoolExecutor源码之后,再来分析这个类的源码。 与之类似的方法:
/** * Creates a thread pool that can schedule commands to run after a * given delay, or to execute periodically. * @param corePoolSize the number of threads to keep in the pool, * even if they are idle * @param threadFactory the factory to use when the executor * creates a new thread * @return a newly created scheduled thread pool * @throws IllegalArgumentException if { @code corePoolSize < 0} * @throws NullPointerException if threadFactory is null */public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory) { return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);}通过这个方法,我们可以指定threadFactory。自定义线程创建的方式。 同样,我们还可以只指定一个线程:
public static ScheduledExecutorService newSingleThreadScheduledExecutor() { return new DelegatedScheduledExecutorService(new ScheduledThreadPoolExecutor(1));}public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) { return new DelegatedScheduledExecutorService(new ScheduledThreadPoolExecutor(1, threadFactory));}上述两个方法都可以实现这个功能,但是需要注意的是,这两个方法的返回在外层包裹了一个包装类。
3.5 newWorkStealingPool这种方式是在jdk1.8之后新增的。我们先来看看其源码:
public LinkedBlockingQueue() { this(Integer.MAX_VALUE);}0这个方法实际上返回的是ForkJoinPool。该方法创建了一
jvm中一个线程调用sleep(),然后发生stw(stop-the-world
Thread.sleep方法的原理在于调用操作系统提供的睡眠功能,此功能挂起线程,由内核启动定时器,超时后恢复线程执行。内核并不介入用户态的垃圾回收(GC)过程。
GC需要停止世界的(STW)时,会先让所有线程到达安全点。而native方法本身即为安全点,因此GC可以与sleep并行进行。当线程恢复执行时,从native方法返回或在native中调用某些JVM方法,如果发现GC的STW还未完成,则必须等待STW结束后才能继续执行。
因此,结论是sleep可以与GC并行,只要在sleep结束时有可用CPU资源立即调度执行,且此时不在STW状态,那么毫秒的延迟就是准确的,即使期间已经执行过多次GC。
JVM调优-CMS常见参数、线程计算与推荐配置
在JVM调优中,CMS GC收集器的常见参数对性能有着显著影响。以下是关键参数的详细介绍:
1. 开启CMS收集器:-XX:+UseConcMarkSweepGC
2.
年轻代并行收集:-XX:UseParNewGC (默认启用)
3.
并行标记:-XX:+CMSParallelRemarkEnabled (默认启用)
4.
并发执行:-XX:+CMSConcurrentMTEnabled (默认启用)
5.
并发CMS线程数:-XX:ConcGCThreads
6.
并行GC线程数:-XX:ParallelGCThreads (默认值由ConcGCThreads决定)
7.
老年代使用率阈值:-XX:CMSInitiatingOccupancyFraction (配合UseCMSInitiatingOccupancyOnly)
8.
启用占用率检查:-XX:+UseCMSInitiatingOccupancyOnly
9.
类对象回收:-XX:+CMSClassUnloadingEnabled (默认关闭)
.
增量模式:-XX:+CMSIncrementalMode (默认关闭)
.
内存压缩:-XX:CMSFullGCsBeforeCompaction
.
预扫描:-XX:+CMSScavengeBeforeRemark (默认关闭)
.
强制使用CMS:-XX:+ExplicitGCInvokesConcurrent
.
包括永久代回收:-XX:+ExplicitGCInvokesConcurrentAndUnloadsClasses
.
忽略系统GC:-XX:+DisableExplicitGC
.
压缩类对象:-XX:UseCompressedOops (默认启用)
.
GC暂停时间:-XX:MaxGCPauseMillis (限制在合理范围内)
对于不同内存配置,推荐如下设置:
- 8CG:推荐4C8G的ParallelGCThreads和ConcGCThreads设置
- 4C8G:推荐的参数配置
- 2C4G:推荐的参数配置
值得注意的是,最大堆内存配置通常不建议与容器或虚拟机内存完全一致,具体原因会在后续文章中详细探讨。在调整这些参数时,需根据应用的具体需求和性能目标进行优化。
JAVA 线ç¨
è¿æ¯javaeyeä¸é常ç»å ¸çå ³äºçº¿ç¨çå¸åï¼åçé常éä¿ææçï¼éåä»»ä½è¯»è®¡ç®æºçåå¦.
线ç¨åæ¥
æ们å¯ä»¥å¨è®¡ç®æºä¸è¿è¡åç§è®¡ç®æºè½¯ä»¶ç¨åºãæ¯ä¸ä¸ªè¿è¡çç¨åºå¯è½å æ¬å¤ä¸ªç¬ç«è¿è¡ç线ç¨ï¼Threadï¼ã
线ç¨ï¼Threadï¼æ¯ä¸ä»½ç¬ç«è¿è¡çç¨åºï¼æèªå·±ä¸ç¨çè¿è¡æ ã线ç¨æå¯è½åå ¶ä»çº¿ç¨å ±äº«ä¸äºèµæºï¼æ¯å¦ï¼å åï¼æ件ï¼æ°æ®åºçã
å½å¤ä¸ªçº¿ç¨åæ¶è¯»ååä¸ä»½å ±äº«èµæºçæ¶åï¼å¯è½ä¼å¼èµ·å²çªãè¿æ¶åï¼æ们éè¦å¼å ¥çº¿ç¨âåæ¥âæºå¶ï¼å³åä½çº¿ç¨ä¹é´è¦æ个å æ¥åå°ï¼ä¸è½ä¸çªèæ¤ä¸å»æ¢ä½ä¸å¢ã
åæ¥è¿ä¸ªè¯æ¯ä»è±æsynchronizeï¼ä½¿åæ¶åçï¼ç¿»è¯è¿æ¥çãæä¹ä¸æç½ä¸ºä»ä¹è¦ç¨è¿ä¸ªå¾å®¹æå¼èµ·è¯¯è§£çè¯ãæ¢ç¶å¤§å®¶é½è¿ä¹ç¨ï¼å±ä»¬ä¹å°±åªå¥½è¿ä¹å°å°±ã
线ç¨åæ¥ççå®ææååé¢æææ°å¥½ç¸åã线ç¨åæ¥ççå®ææï¼å ¶å®æ¯âæéâï¼å 个线ç¨ä¹é´è¦æéï¼ä¸ä¸ªä¸ä¸ªå¯¹å ±äº«èµæºè¿è¡æä½ï¼èä¸æ¯åæ¶è¿è¡æä½ã
å æ¤ï¼å ³äºçº¿ç¨åæ¥ï¼éè¦ç¢ç¢è®°ä½ç第ä¸ç¹æ¯ï¼çº¿ç¨åæ¥å°±æ¯çº¿ç¨æéãåæ¥å°±æ¯æéã线ç¨åæ¥çç®çå°±æ¯é¿å 线ç¨âåæ¥âæ§è¡ãè¿å¯çæ¯ä¸ªæ èçç»å£ä»¤ã
å ³äºçº¿ç¨åæ¥ï¼éè¦ç¢ç¢è®°ä½ç第äºç¹æ¯ âå ±äº«âè¿ä¸¤ä¸ªåãåªæå ±äº«èµæºç读å访é®æéè¦åæ¥ãå¦æä¸æ¯å ±äº«èµæºï¼é£ä¹å°±æ ¹æ¬æ²¡æåæ¥çå¿ è¦ã
å ³äºçº¿ç¨åæ¥ï¼éè¦ç¢ç¢è®°ä½ç第ä¸ç¹æ¯ï¼åªæâåéâæéè¦åæ¥è®¿é®ãå¦æå ±äº«çèµæºæ¯åºå®ä¸åçï¼é£ä¹å°±ç¸å½äºâ常éâï¼çº¿ç¨åæ¶è¯»å常éä¹ä¸éè¦åæ¥ãè³å°ä¸ä¸ªçº¿ç¨ä¿®æ¹å ±äº«èµæºï¼è¿æ ·çæ åµä¸ï¼çº¿ç¨ä¹é´å°±éè¦åæ¥ã
å ³äºçº¿ç¨åæ¥ï¼éè¦ç¢ç¢è®°ä½ç第åç¹æ¯ï¼å¤ä¸ªçº¿ç¨è®¿é®å ±äº«èµæºç代ç æå¯è½æ¯åä¸ä»½ä»£ç ï¼ä¹æå¯è½æ¯ä¸åç代ç ï¼æ 论æ¯å¦æ§è¡åä¸ä»½ä»£ç ï¼åªè¦è¿äºçº¿ç¨ç代ç 访é®åä¸ä»½å¯åçå ±äº«èµæºï¼è¿äºçº¿ç¨ä¹é´å°±éè¦åæ¥ã
为äºå æ·±ç解ï¼ä¸é¢ä¸¾å 个ä¾åã
æ两个éè´åï¼ä»ä»¬çå·¥ä½å 容æ¯ç¸åçï¼é½æ¯éµå¾ªå¦ä¸çæ¥éª¤ï¼
ï¼1ï¼å°å¸åºä¸å»ï¼å¯»æ¾å¹¶è´ä¹°ææ½åçæ ·åã
ï¼2ï¼åå°å ¬å¸ï¼åæ¥åã
è¿ä¸¤ä¸ªäººçå·¥ä½å 容è½ç¶ä¸æ ·ï¼ä»ä»¬é½éè¦è´ä¹°æ ·åï¼ä»ä»¬å¯è½ä¹°å°åæ ·ç§ç±»çæ ·åï¼ä½æ¯ä»ä»¬ç»å¯¹ä¸ä¼è´ä¹°å°åä¸ä»¶æ ·åï¼ä»ä»¬ä¹é´æ²¡æä»»ä½å ±äº«èµæºãæ以ï¼ä»ä»¬å¯ä»¥åèªè¿è¡èªå·±çå·¥ä½ï¼äºä¸å¹²æ°ã
è¿ä¸¤ä¸ªéè´åå°±ç¸å½äºä¸¤ä¸ªçº¿ç¨ï¼ä¸¤ä¸ªéè´åéµå¾ªç¸åçå·¥ä½æ¥éª¤ï¼ç¸å½äºè¿ä¸¤ä¸ªçº¿ç¨æ§è¡åä¸æ®µä»£ç ã
ä¸é¢ç»è¿ä¸¤ä¸ªéè´åå¢å ä¸ä¸ªå·¥ä½æ¥éª¤ãéè´åéè¦æ ¹æ®å ¬å¸çâå¸åæ âä¸é¢å ¬å¸çä¿¡æ¯ï¼å®æèªå·±çå·¥ä½è®¡åã
è¿ä¸¤ä¸ªéè´åæå¯è½åæ¶èµ°å°å¸åæ çåé¢ï¼åæ¶è§çå¸åæ ä¸çä¿¡æ¯ãè¿ä¸ç¹é®é¢é½æ²¡æãå 为å¸åæ æ¯åªè¯»çï¼è¿ä¸¤ä¸ªéè´åè°é½ä¸ä¼å»ä¿®æ¹å¸åæ ä¸åçä¿¡æ¯ã
ä¸é¢å¢å ä¸ä¸ªè§è²ãä¸ä¸ªåå ¬å®¤è¡æ¿äººåè¿ä¸ªæ¶åï¼ä¹èµ°å°äºå¸åæ åé¢ï¼åå¤ä¿®æ¹å¸åæ ä¸çä¿¡æ¯ã
å¦æè¡æ¿äººåå å°è¾¾å¸åæ ï¼å¹¶ä¸æ£å¨ä¿®æ¹å¸åæ çå 容ã两个éè´åè¿ä¸ªæ¶åï¼æ°å¥½ä¹å°äºãè¿ä¸¤ä¸ªéè´åå°±å¿ é¡»çå¾ è¡æ¿äººåå®æä¿®æ¹ä¹åï¼æè½è§çä¿®æ¹åçä¿¡æ¯ã
å¦æè¡æ¿äººåå°è¾¾çæ¶åï¼ä¸¤ä¸ªéè´åå·²ç»å¨è§çå¸åæ äºãé£ä¹è¡æ¿äººåéè¦çå¾ ä¸¤ä¸ªéè´åæå½åä¿¡æ¯è®°å½ä¸æ¥ä¹åï¼æè½å¤åä¸æ°çä¿¡æ¯ã
ä¸è¿°è¿ä¸¤ç§æ åµï¼è¡æ¿äººååéè´å对å¸åæ ç访é®å°±éè¦è¿è¡åæ¥ãå ä¸ºå ¶ä¸ä¸ä¸ªçº¿ç¨ï¼è¡æ¿äººåï¼ä¿®æ¹äºå ±äº«èµæºï¼å¸åæ ï¼ãèä¸æ们å¯ä»¥çå°ï¼è¡æ¿äººåçå·¥ä½æµç¨åéè´åçå·¥ä½æµç¨ï¼æ§è¡ä»£ç ï¼å®å ¨ä¸åï¼ä½æ¯ç±äºä»ä»¬è®¿é®äºåä¸ä»½å¯åå ±äº«èµæºï¼å¸åæ ï¼ï¼æ以ä»ä»¬ä¹é´éè¦åæ¥ã
åæ¥é
åé¢è®²äºä¸ºä»ä¹è¦çº¿ç¨åæ¥ï¼ä¸é¢æ们就æ¥çå¦ä½æè½çº¿ç¨åæ¥ã
线ç¨åæ¥çåºæ¬å®ç°æè·¯è¿æ¯æ¯è¾å®¹æç解çãæ们å¯ä»¥ç»å ±äº«èµæºå ä¸æéï¼è¿æéåªæä¸æé¥åãåªä¸ªçº¿ç¨è·åäºè¿æé¥åï¼æææå©è®¿é®è¯¥å ±äº«èµæºã
çæ´»ä¸ï¼æ们ä¹å¯è½ä¼éå°è¿æ ·çä¾åãä¸äºè¶ å¸çå¤é¢æä¾äºä¸äºèªå¨å¨ç©ç®±ãæ¯ä¸ªå¨ç©ç®±é½æä¸æéï¼ä¸æé¥åã人们å¯ä»¥ä½¿ç¨é£äºå¸¦æé¥åçå¨ç©ç®±ï¼æä¸è¥¿æ¾å°å¨ç©ç®±éé¢ï¼æå¨ç©ç®±éä¸ï¼ç¶åæé¥åæ¿èµ°ãè¿æ ·ï¼è¯¥å¨ç©ç®±å°±è¢«éä½äºï¼å ¶ä»äººä¸è½å访é®è¿ä¸ªå¨ç©ç®±ãï¼å½ç¶ï¼çå®çå¨ç©ç®±é¥åæ¯å¯ä»¥è¢«äººæ¿èµ°å¤å¶çï¼æ以ä¸è¦æè´µéç©åæ¾å¨è¶ å¸çå¨ç©ç®±éé¢ãäºæ¯å¾å¤è¶ å¸é½éç¨äºçµåå¯ç éãï¼
线ç¨åæ¥éè¿ä¸ªæ¨¡åçèµ·æ¥å¾ç´è§ãä½æ¯ï¼è¿æä¸ä¸ªä¸¥å³»çé®é¢æ²¡æ解å³ï¼è¿ä¸ªåæ¥éåºè¯¥å å¨åªéï¼
å½ç¶æ¯å å¨å ±äº«èµæºä¸äºãååºå¿«ç读è ä¸å®ä¼æ¢å åçã
没éï¼å¦æå¯è½ï¼æ们å½ç¶å°½éæåæ¥éå å¨å ±äº«èµæºä¸ãä¸äºæ¯è¾å®åçå ±äº«èµæºï¼æ¯å¦ï¼æ件系ç»ï¼æ°æ®åºç³»ç»çï¼èªèº«é½æä¾äºæ¯è¾å®åçåæ¥éæºå¶ãæ们ä¸ç¨å¦å¤ç»è¿äºèµæºå éï¼è¿äºèµæºèªå·±å°±æéã
ä½æ¯ï¼å¤§é¨åæ åµä¸ï¼æ们å¨ä»£ç ä¸è®¿é®çå ±äº«èµæºé½æ¯æ¯è¾ç®åçå ±äº«å¯¹è±¡ãè¿äºå¯¹è±¡éé¢æ²¡æå°æ¹è®©æ们å éã
读è å¯è½ä¼æåºå»ºè®®ï¼ä¸ºä»ä¹ä¸å¨æ¯ä¸ä¸ªå¯¹è±¡å é¨é½å¢å ä¸ä¸ªæ°çåºåï¼ä¸é¨ç¨æ¥å éå¢ï¼è¿ç§è®¾è®¡ç论ä¸å½ç¶ä¹æ¯å¯è¡çãé®é¢å¨äºï¼çº¿ç¨åæ¥çæ åµå¹¶ä¸æ¯å¾æ®éãå¦æå 为è¿å°æ¦çäºä»¶ï¼å¨ææ对象å é¨é½å¼è¾ä¸åé空é´ï¼å°ä¼å¸¦æ¥æ大ç空é´æµªè´¹ãå¾ä¸å¿å¤±ã
äºæ¯ï¼ç°ä»£çç¼ç¨è¯è¨ç设计æè·¯é½æ¯æåæ¥éå å¨ä»£ç 段ä¸ãç¡®åç说ï¼æ¯æåæ¥éå å¨â访é®å ±äº«èµæºç代ç 段âä¸ãè¿ä¸ç¹ä¸å®è¦è®°ä½ï¼åæ¥éæ¯å å¨ä»£ç 段ä¸çã
åæ¥éå å¨ä»£ç 段ä¸ï¼å°±å¾å¥½å°è§£å³äºä¸è¿°ç空é´æµªè´¹é®é¢ãä½æ¯å´å¢å äºæ¨¡åçå¤æ度ï¼ä¹å¢å äºæ们çç解é¾åº¦ã
ç°å¨æ们就æ¥ä»ç»åæâåæ¥éå å¨ä»£ç 段ä¸âç线ç¨åæ¥æ¨¡åã
é¦å ï¼æ们已ç»è§£å³äºåæ¥éå å¨åªéçé®é¢ãæ们已ç»ç¡®å®ï¼åæ¥éä¸æ¯å å¨å ±äº«èµæºä¸ï¼èæ¯å å¨è®¿é®å ±äº«èµæºç代ç 段ä¸ã
å ¶æ¬¡ï¼æ们è¦è§£å³çé®é¢æ¯ï¼æ们åºè¯¥å¨ä»£ç 段ä¸å ä»ä¹æ ·çéãè¿ä¸ªé®é¢æ¯éç¹ä¸çéç¹ãè¿æ¯æä»¬å°¤å ¶è¦æ³¨æçé®é¢ï¼è®¿é®åä¸ä»½å ±äº«èµæºçä¸å代ç 段ï¼åºè¯¥å ä¸åä¸ä¸ªåæ¥éï¼å¦æå çæ¯ä¸åçåæ¥éï¼é£ä¹æ ¹æ¬å°±èµ·ä¸å°åæ¥çä½ç¨ï¼æ²¡æä»»ä½æä¹ã
è¿å°±æ¯è¯´ï¼åæ¥éæ¬èº«ä¹ä¸å®æ¯å¤ä¸ªçº¿ç¨ä¹é´çå ±äº«å¯¹è±¡ã
Javaè¯è¨çsynchronizedå ³é®å
为äºå æ·±ç解ï¼ä¸¾å 个代ç 段åæ¥çä¾åã
ä¸åè¯è¨çåæ¥é模åé½æ¯ä¸æ ·çãåªæ¯è¡¨è¾¾æ¹å¼æäºä¸åãè¿éæ们以å½åææµè¡çJavaè¯è¨ä¸ºä¾ãJavaè¯è¨éé¢ç¨synchronizedå ³é®åç»ä»£ç 段å éãæ´ä¸ªè¯æ³å½¢å¼è¡¨ç°ä¸º
synchronized(åæ¥é) {
// 访é®å ±äº«èµæºï¼éè¦åæ¥ç代ç 段
}
è¿éå°¤å ¶è¦æ³¨æçå°±æ¯ï¼åæ¥éæ¬èº«ä¸å®è¦æ¯å ±äº«ç对象ã
⦠f1() {
Object lock1 = new Object(); // 产çä¸ä¸ªåæ¥é
synchronized(lock1){
// 代ç 段 A
// 访é®å ±äº«èµæº resource1
// éè¦åæ¥
}
}
ä¸é¢è¿æ®µä»£ç 没æä»»ä½æä¹ãå 为é£ä¸ªåæ¥éæ¯å¨å½æ°ä½å é¨äº§ççãæ¯ä¸ªçº¿ç¨è°ç¨è¿æ®µä»£ç çæ¶åï¼é½ä¼äº§çä¸ä¸ªæ°çåæ¥éãé£ä¹å¤ä¸ªçº¿ç¨ä¹é´ï¼ä½¿ç¨çæ¯ä¸åçåæ¥éãæ ¹æ¬è¾¾ä¸å°åæ¥çç®çã
åæ¥ä»£ç ä¸å®è¦åæå¦ä¸çå½¢å¼ï¼æææä¹ã
public static final Object lock1 = new Object();
⦠f1() {
synchronized(lock1){ // lock1 æ¯å ¬ç¨åæ¥é
// 代ç 段 A
// 访é®å ±äº«èµæº resource1
// éè¦åæ¥
}
ä½ ä¸ä¸å®è¦æåæ¥é声æ为staticæè publicï¼ä½æ¯ä½ ä¸å®è¦ä¿è¯ç¸å ³çåæ¥ä»£ç ä¹é´ï¼ä¸å®è¦ä½¿ç¨åä¸ä¸ªåæ¥éã
讲å°è¿éï¼ä½ ä¸å®ä¼å¥½å¥ï¼è¿ä¸ªåæ¥éå°åºæ¯ä¸ªä»ä¹ä¸è¥¿ã为ä»ä¹é便声æä¸ä¸ªObject对象ï¼å°±å¯ä»¥ä½ä¸ºåæ¥éï¼
å¨Javaéé¢ï¼åæ¥éçæ¦å¿µå°±æ¯è¿æ ·çãä»»ä½ä¸ä¸ªObject Referenceé½å¯ä»¥ä½ä¸ºåæ¥éãæ们å¯ä»¥æObject Referenceç解为对象å¨å ååé ç³»ç»ä¸çå åå°åãå æ¤ï¼è¦ä¿è¯åæ¥ä»£ç 段ä¹é´ä½¿ç¨çæ¯åä¸ä¸ªåæ¥éï¼æ们就è¦ä¿è¯è¿äºåæ¥ä»£ç 段çsynchronizedå ³é®å使ç¨çæ¯åä¸ä¸ªObject Referenceï¼åä¸ä¸ªå åå°åãè¿ä¹æ¯ä¸ºä»ä¹æå¨åé¢ç代ç ä¸å£°ælock1çæ¶åï¼ä½¿ç¨äºfinalå ³é®åï¼è¿å°±æ¯ä¸ºäºä¿è¯lock1çObject Referenceå¨æ´ä¸ªç³»ç»è¿è¡è¿ç¨ä¸é½ä¿æä¸åã
ä¸äºæ±ç¥æ¬²å¼ºç读è å¯è½æ³è¦ç»§ç»æ·±å ¥äºè§£synchronzied(åæ¥é)çå®é è¿è¡æºå¶ãJavaèææºè§èä¸ï¼ä½ å¯ä»¥å¨googleç¨âJVM Specâçå ³é®åè¿è¡æç´¢ï¼ï¼æ对synchronizedå ³é®åç详ç»è§£éãsynchronizedä¼ç¼è¯æ monitor enter, ⦠monitor exitä¹ç±»çæ令对ãMonitorå°±æ¯å®é ä¸çåæ¥éãæ¯ä¸ä¸ªObject Referenceå¨æ¦å¿µä¸é½å¯¹åºä¸ä¸ªmonitorã
è¿äºå®ç°ç»èé®é¢ï¼å¹¶ä¸æ¯ç解åæ¥é模åçå ³é®ãæ们继ç»çå 个ä¾åï¼å 深对åæ¥é模åçç解ã
public static final Object lock1 = new Object();
⦠f1() {
synchronized(lock1){ // lock1 æ¯å ¬ç¨åæ¥é
// 代ç 段 A
// 访é®å ±äº«èµæº resource1
// éè¦åæ¥
}
}
⦠f2() {
synchronized(lock1){ // lock1 æ¯å ¬ç¨åæ¥é
// 代ç 段 B
// 访é®å ±äº«èµæº resource1
// éè¦åæ¥
}
}
ä¸è¿°ç代ç ä¸ï¼ä»£ç 段Aå代ç 段Bå°±æ¯åæ¥çãå 为å®ä»¬ä½¿ç¨çæ¯åä¸ä¸ªåæ¥élock1ã
å¦ææ个线ç¨åæ¶æ§è¡ä»£ç 段Aï¼åæ¶è¿æ个线ç¨åæ¶æ§è¡ä»£ç 段Bï¼é£ä¹è¿ä¸ªçº¿ç¨ä¹é´é½æ¯è¦è¿è¡åæ¥çã
è¿ä¸ªçº¿ç¨é½è¦ç«äºä¸ä¸ªåæ¥élock1ãåä¸æ¶å»ï¼åªæä¸ä¸ªçº¿ç¨è½å¤è·å¾lock1çæææï¼åªæä¸ä¸ªçº¿ç¨å¯ä»¥æ§è¡ä»£ç 段Aæè 代ç 段Bãå ¶ä»ç«äºå¤±è´¥ç线ç¨åªè½æåè¿è¡ï¼è¿å ¥å°è¯¥åæ¥éç就绪ï¼Readyï¼éåã
æ¯ä¸ä¸ªåæ¥éä¸é¢é½æäºå 个线ç¨éåï¼å æ¬å°±ç»ªï¼Readyï¼éåï¼å¾ å¬ï¼Waitingï¼éåçãæ¯å¦ï¼lock1对åºç就绪éåå°±å¯ä»¥å«ålock1 - ready queueãæ¯ä¸ªéåéé¢é½å¯è½æå¤ä¸ªæåè¿è¡ç线ç¨ã
注æï¼ç«äºåæ¥é失败ç线ç¨è¿å ¥çæ¯è¯¥åæ¥éç就绪ï¼Readyï¼éåï¼èä¸æ¯åé¢è¦è®²è¿°çå¾ å¬éåï¼Waiting Queueï¼ä¹å¯ä»¥ç¿»è¯ä¸ºçå¾ éåï¼ã就绪éåéé¢ç线ç¨æ»æ¯æ¶å»åå¤çç«äºåæ¥éï¼æ¶å»åå¤çè¿è¡ãèå¾ å¬éåéé¢ç线ç¨ååªè½ä¸ç´çå¾ ï¼ç´å°çå°æ个信å·çéç¥ä¹åï¼æè½å¤è½¬ç§»å°å°±ç»ªéåä¸ï¼åå¤è¿è¡ã
æåè·ååæ¥éç线ç¨ï¼æ§è¡å®åæ¥ä»£ç 段ä¹åï¼ä¼éæ¾åæ¥éã该åæ¥éç就绪éåä¸çå ¶ä»çº¿ç¨å°±ç»§ç»ä¸ä¸è½®åæ¥éçç«äºãæåè å°±å¯ä»¥ç»§ç»è¿è¡ï¼å¤±è´¥è è¿æ¯è¦ä¹ä¹å°å¾ å¨å°±ç»ªéåä¸ã
å æ¤ï¼çº¿ç¨åæ¥æ¯é常èè´¹èµæºçä¸ç§æä½ãæ们è¦å°½éæ§å¶çº¿ç¨åæ¥ç代ç 段èå´ãåæ¥ç代ç 段èå´è¶å°è¶å¥½ãæ们ç¨ä¸ä¸ªåè¯âåæ¥ç²åº¦âæ¥è¡¨ç¤ºåæ¥ä»£ç 段çèå´ã
åæ¥ç²åº¦
å¨Javaè¯è¨éé¢ï¼æ们å¯ä»¥ç´æ¥æsynchronizedå ³é®åç´æ¥å å¨å½æ°çå®ä¹ä¸ã
æ¯å¦ã
⦠synchronized ⦠f1() {
// f1 代ç 段
}
è¿æ®µä»£ç å°±çä»·äº
⦠f1() {
synchronized(this){ // åæ¥éå°±æ¯å¯¹è±¡æ¬èº«
// f1 代ç 段
}
}
åæ ·çååéç¨äºéæï¼staticï¼å½æ°
æ¯å¦ã
⦠static synchronized ⦠f1() {
// f1 代ç 段
}
è¿æ®µä»£ç å°±çä»·äº
â¦static ⦠f1() {
synchronized(Class.forName(â¦)){ // åæ¥éæ¯ç±»å®ä¹æ¬èº«
// f1 代ç 段
}
}
ä½æ¯ï¼æ们è¦å°½éé¿å è¿ç§ç´æ¥æsynchronizedå å¨å½æ°å®ä¹ä¸çå·æåæ³ãå 为æ们è¦æ§å¶åæ¥ç²åº¦ãåæ¥ç代ç 段è¶å°è¶å¥½ãsynchronizedæ§å¶çèå´è¶å°è¶å¥½ã
æ们ä¸ä» è¦å¨ç¼©å°åæ¥ä»£ç 段çé¿åº¦ä¸ä¸å夫ï¼æ们åæ¶è¿è¦æ³¨æç»ååæ¥éã
æ¯å¦ï¼ä¸é¢ç代ç
public static final Object lock1 = new Object();
⦠f1() {
synchronized(lock1){ // lock1 æ¯å ¬ç¨åæ¥é
// 代ç 段 A
// 访é®å ±äº«èµæº resource1
// éè¦åæ¥
}
}
⦠f2() {
synchronized(lock1){ // lock1 æ¯å ¬ç¨åæ¥é
// 代ç 段 B
// 访é®å ±äº«èµæº resource1
// éè¦åæ¥
}
}
⦠f3() {
synchronized(lock1){ // lock1 æ¯å ¬ç¨åæ¥é
// 代ç 段 C
// 访é®å ±äº«èµæº resource2
// éè¦åæ¥
}
}
⦠f4() {
synchronized(lock1){ // lock1 æ¯å ¬ç¨åæ¥é
// 代ç 段 D
// 访é®å ±äº«èµæº resource2
// éè¦åæ¥
}
}
ä¸è¿°ç4段åæ¥ä»£ç ï¼ä½¿ç¨åä¸ä¸ªåæ¥élock1ãææè°ç¨4段代ç ä¸ä»»ä½ä¸æ®µä»£ç ç线ç¨ï¼é½éè¦ç«äºåä¸ä¸ªåæ¥élock1ã
æ们ä»ç»åæä¸ä¸ï¼åç°è¿æ¯æ²¡æå¿ è¦çã
å 为f1()ç代ç 段Aåf2()ç代ç 段B访é®çå ±äº«èµæºæ¯resource1ï¼f3()ç代ç 段Cåf4()ç代ç 段D访é®çå ±äº«èµæºæ¯resource2ï¼å®ä»¬æ²¡æå¿ è¦é½ç«äºåä¸ä¸ªåæ¥élock1ãæ们å¯ä»¥å¢å ä¸ä¸ªåæ¥élock2ãf3()åf4()ç代ç å¯ä»¥ä¿®æ¹ä¸ºï¼
public static final Object lock2 = new Object();
⦠f3() {
synchronized(lock2){ // lock2 æ¯å ¬ç¨åæ¥é
// 代ç 段 C
// 访é®å ±äº«èµæº resource2
// éè¦åæ¥
}
}
⦠f4() {
synchronized(lock2){ // lock2 æ¯å ¬ç¨åæ¥é
// 代ç 段 D
// 访é®å ±äº«èµæº resource2
// éè¦åæ¥
}
}
è¿æ ·ï¼f1()åf2()å°±ä¼ç«äºlock1ï¼èf3()åf4()å°±ä¼ç«äºlock2ãè¿æ ·ï¼åå¼æ¥åå«ç«äºä¸¤ä¸ªéï¼å°±å¯ä»¥å¤§å¤§è¾å°åæ¥éç«äºçæ¦çï¼ä»èåå°ç³»ç»çå¼éã
ä¿¡å·é
åæ¥é模ååªæ¯æç®åçåæ¥æ¨¡åãåä¸æ¶å»ï¼åªæä¸ä¸ªçº¿ç¨è½å¤è¿è¡åæ¥ä»£ç ã
æçæ¶åï¼æ们å¸æå¤çæ´å å¤æçåæ¥æ¨¡åï¼æ¯å¦ç产è /æ¶è´¹è 模åã读ååæ¥æ¨¡åçãè¿ç§æ åµä¸ï¼åæ¥é模åå°±ä¸å¤ç¨äºãæ们éè¦ä¸ä¸ªæ°ç模åãè¿å°±æ¯æ们è¦è®²è¿°çä¿¡å·é模åã
ä¿¡å·é模åçå·¥ä½æ¹å¼å¦ä¸ï¼çº¿ç¨å¨è¿è¡çè¿ç¨ä¸ï¼å¯ä»¥ä¸»å¨åä¸æ¥ï¼çå¾ æ个信å·éçéç¥ï¼è¿æ¶åï¼è¯¥çº¿ç¨å°±è¿å ¥å°è¯¥ä¿¡å·éçå¾ å¬ï¼Waitingï¼éåå½ä¸ï¼çå°éç¥ä¹åï¼å继ç»è¿è¡ã
å¾å¤è¯è¨éé¢ï¼åæ¥éé½ç±ä¸é¨ç对象表示ï¼å¯¹è±¡åé常å«Monitorã
åæ ·ï¼å¨å¾å¤è¯è¨ä¸ï¼ä¿¡å·éé常ä¹æä¸é¨ç对象åæ¥è¡¨ç¤ºï¼æ¯å¦ï¼Mutexï¼Semphoreã
ä¿¡å·é模åè¦æ¯åæ¥é模åå¤æ许å¤ãä¸äºç³»ç»ä¸ï¼ä¿¡å·éçè³å¯ä»¥è·¨è¿ç¨è¿è¡åæ¥ãå¦å¤ä¸äºä¿¡å·éçè³è¿æ计æ°åè½ï¼è½å¤æ§å¶åæ¶è¿è¡ç线ç¨æ°ã
æ们没æå¿ è¦èèé£ä¹å¤æç模åãææé£äºå¤æç模åï¼é½æ¯æåºæ¬ç模åè¡çåºæ¥çãåªè¦ææ¡äºæåºæ¬çä¿¡å·é模åâââçå¾ /éç¥â模åï¼å¤æ模åä¹å°±è¿åè解äºã
æ们è¿æ¯ä»¥Javaè¯è¨ä¸ºä¾ãJavaè¯è¨éé¢çåæ¥éåä¿¡å·éæ¦å¿µé½é常模ç³ï¼æ²¡æä¸é¨ç对象åè¯æ¥è¡¨ç¤ºåæ¥éåä¿¡å·éï¼åªæ两个åæ¥éç¸å ³çå ³é®åââvolatileåsynchronizedã
è¿ç§æ¨¡ç³è½ç¶å¯¼è´æ¦å¿µä¸æ¸ ï¼ä½åæ¶ä¹é¿å äºMonitorãMutexãSemphoreçåè¯å¸¦æ¥çç§ç§è¯¯è§£ãæ们ä¸å¿ æ§çäºåè¯ä¹äºï¼å¯ä»¥ä¸æ³¨äºç解å®é çè¿è¡åçã
å¨Javaè¯è¨éé¢ï¼ä»»ä½ä¸ä¸ªObject Referenceé½å¯ä»¥ä½ä¸ºåæ¥éãåæ ·çéçï¼ä»»ä½ä¸ä¸ªObject Referenceä¹å¯ä»¥ä½ä¸ºä¿¡å·éã
Object对象çwait()æ¹æ³å°±æ¯çå¾ éç¥ï¼Object对象çnotify()æ¹æ³å°±æ¯ååºéç¥ã
å ·ä½è°ç¨æ¹æ³ä¸º
ï¼1ï¼çå¾ æ个信å·éçéç¥
public static final Object signal = new Object();
⦠f1() {
synchronized(singal) { // é¦å æ们è¦è·åè¿ä¸ªä¿¡å·éãè¿ä¸ªä¿¡å·éåæ¶ä¹æ¯ä¸ä¸ªåæ¥é
// åªææåè·åäºsignalè¿ä¸ªä¿¡å·éå ¼åæ¥éä¹åï¼æ们æå¯è½è¿å ¥è¿æ®µä»£ç
signal.wait(); // è¿éè¦æ¾å¼ä¿¡å·éãæ¬çº¿ç¨è¦è¿å ¥signalä¿¡å·éçå¾ å¬ï¼Waitingï¼éå
// å¯æãè¾è¾è¦è¦äºåå°æçä¿¡å·éï¼å°±è¿ä¹è¢«æ¾å¼äº
// çå°éç¥ä¹åï¼ä»å¾ å¬ï¼Waitingï¼éå转å°å°±ç»ªï¼Readyï¼éåéé¢
// 转å°äºå°±ç»ªéåä¸ï¼ç¦»CPUæ ¸å¿è¿äºä¸æ¥ï¼å°±ææºä¼ç»§ç»æ§è¡ä¸é¢ç代ç äºã
// ä»ç¶éè¦æsignalåæ¥éç«äºå°æï¼æè½å¤çæ£ç»§ç»æ§è¡ä¸é¢ç代ç ãå½è¦åã
â¦
}
}
éè¦æ³¨æçæ¯ï¼ä¸è¿°ä»£ç ä¸çsignal.wait()çææãsignal.wait()å¾å®¹æ导è´è¯¯è§£ãsignal.wait()çææ并ä¸æ¯è¯´ï¼signalå¼å§waitï¼èæ¯è¯´ï¼è¿è¡è¿æ®µä»£ç çå½å线ç¨å¼å§waitè¿ä¸ªsignal对象ï¼å³è¿å ¥signal对象çå¾ å¬ï¼Waitingï¼éåã
ï¼2ï¼ååºæ个信å·éçéç¥
⦠f2() {
synchronized(singal) { // é¦å ï¼æ们åæ ·è¦è·åè¿ä¸ªä¿¡å·éãåæ¶ä¹æ¯ä¸ä¸ªåæ¥éã
// åªææåè·åäºsignalè¿ä¸ªä¿¡å·éå ¼åæ¥éä¹åï¼æ们æå¯è½è¿å ¥è¿æ®µä»£ç
signal.notify(); // è¿éï¼æ们éç¥signalçå¾ å¬éåä¸çæ个线ç¨ã
// å¦ææ个线ç¨çå°äºè¿ä¸ªéç¥ï¼é£ä¸ªçº¿ç¨å°±ä¼è½¬å°å°±ç»ªéåä¸
// ä½æ¯æ¬çº¿ç¨ä»ç¶ç»§ç»æ¥æsignalè¿ä¸ªåæ¥éï¼æ¬çº¿ç¨ä»ç¶ç»§ç»æ§è¡
// å¿å¿ï¼è½ç¶æ¬çº¿ç¨å¥½å¿éç¥å ¶ä»çº¿ç¨ï¼
// ä½æ¯ï¼æ¬çº¿ç¨å¯æ²¡æé£ä¹é«é£äº®èï¼æ¾å¼å°æçåæ¥é
// æ¬çº¿ç¨ç»§ç»æ§è¡ä¸é¢ç代ç
â¦
}
}
éè¦æ³¨æçæ¯ï¼signal.notify()çææãsignal.notify()并ä¸æ¯éç¥signalè¿ä¸ªå¯¹è±¡æ¬èº«ãèæ¯éç¥æ£å¨çå¾ signalä¿¡å·éçå ¶ä»çº¿ç¨ã
以ä¸å°±æ¯Objectçwait()ånotify()çåºæ¬ç¨æ³ã
å®é ä¸ï¼wait()è¿å¯ä»¥å®ä¹çå¾ æ¶é´ï¼å½çº¿ç¨å¨æä¿¡å·éçå¾ å¬éåä¸ï¼çå°è¶³å¤é¿çæ¶é´ï¼å°±ä¼çæ å¯çï¼æ éåçï¼èªå·±å°±ä»å¾ å¬éå转移å°å°±ç»ªéåä¸äºã
å¦å¤ï¼è¿æä¸ä¸ªnotifyAll()æ¹æ³ï¼è¡¨ç¤ºéç¥å¾ å¬éåéé¢çææ线ç¨ã
è¿äºç»èé®é¢ï¼å¹¶ä¸å¯¹å¤§å±äº§çå½±åã
绿è²çº¿ç¨
绿è²çº¿ç¨ï¼Green Threadï¼æ¯ä¸ä¸ªç¸å¯¹äºæä½ç³»ç»çº¿ç¨ï¼Native Threadï¼çæ¦å¿µã
æä½ç³»ç»çº¿ç¨ï¼Native Threadï¼çææå°±æ¯ï¼ç¨åºéé¢ç线ç¨ä¼çæ£æ å°å°æä½ç³»ç»ç线ç¨ï¼çº¿ç¨çè¿è¡åè°åº¦é½æ¯ç±æä½ç³»ç»æ§å¶ç
绿è²çº¿ç¨ï¼Green Threadï¼çæææ¯ï¼ç¨åºéé¢ç线ç¨ä¸ä¼çæ£æ å°å°æä½ç³»ç»ç线ç¨ï¼èæ¯ç±è¯è¨è¿è¡å¹³å°èªèº«æ¥è°åº¦ã
å½åçæ¬çPythonè¯è¨ç线ç¨å°±å¯ä»¥æ å°å°æä½ç³»ç»çº¿ç¨ãå½åçæ¬çRubyè¯è¨ç线ç¨å°±å±äºç»¿è²çº¿ç¨ï¼æ æ³æ å°å°æä½ç³»ç»ç线ç¨ï¼å æ¤Rubyè¯è¨ç线ç¨çè¿è¡é度æ¯è¾æ ¢ã
é¾é说ï¼ç»¿è²çº¿ç¨è¦æ¯æä½ç³»ç»çº¿ç¨è¦æ ¢åï¼å½ç¶ä¸æ¯è¿æ ·ãäºå®ä¸ï¼æ åµå¯è½æ£å¥½ç¸åãRubyæ¯ä¸ä¸ªç¹æ®çä¾åã线ç¨è°åº¦å¨å¹¶ä¸æ¯å¾æçã
ç®åï¼çº¿ç¨çæµè¡å®ç°æ¨¡åå°±æ¯ç»¿è²çº¿ç¨ãæ¯å¦ï¼stackless Pythonï¼å°±å¼å ¥äºæ´å è½»éç绿è²çº¿ç¨æ¦å¿µãå¨çº¿ç¨å¹¶åç¼ç¨æ¹é¢ï¼æ 论æ¯è¿è¡é度è¿æ¯å¹¶åè´è½½ä¸ï¼é½ä¼äºPythonã
å¦ä¸ä¸ªæ´èåçä¾åå°±æ¯ErLangï¼ç±ç«ä¿¡å ¬å¸å¼åçä¸ç§å¼æºè¯è¨ï¼ã
ErLangç绿è²çº¿ç¨æ¦å¿µé常彻åºãErLangç线ç¨ä¸å«Threadï¼èæ¯å«åProcessãè¿å¾å®¹æåè¿ç¨æ··æ·èµ·æ¥ãè¿éè¦æ³¨æåºåä¸ä¸ã
ErLang Processä¹é´æ ¹æ¬å°±ä¸éè¦åæ¥ãå 为ErLangè¯è¨çææåéé½æ¯finalçï¼ä¸å 许åéçå¼åçä»»ä½ååãå æ¤æ ¹æ¬å°±ä¸éè¦åæ¥ã
finalåéçå¦ä¸ä¸ªå¥½å¤å°±æ¯ï¼å¯¹è±¡ä¹é´ä¸å¯è½åºç°äº¤åå¼ç¨ï¼ä¸å¯è½ææä¸ç§ç¯ç¶çå ³èï¼å¯¹è±¡ä¹é´çå ³èé½æ¯ååçï¼æ ç¶çãå æ¤ï¼å ååå¾åæ¶çç®æ³æçä¹é常é«ãè¿å°±è®©ErLangè½å¤è¾¾å°Soft Real Timeï¼è½¯å®æ¶ï¼çææãè¿å¯¹äºä¸é¨æ¯æå ååå¾åæ¶çè¯è¨æ¥è¯´ï¼å¯ä¸æ¯ä¸ä»¶å®¹æçäºæ ã