那个html爱心代码码中的Thread.sleep(millis;100);哪里错了?

launch { //在后台启动新的协程并继续

注意,newSingleThreadContext创建一个新线程,这是一个非常昂贵的资源。在实际应用程序中,它必须在不再需要时释放,使用close 函数,或者存储在顶级变量中并在整个应用程序中重用。

无限制与受限制的调度员

该开敞协程调度员开始协程在调用线程,但直到第一个悬挂点。暂停后,它将在线程中恢复,该线程完全由调用的挂起函数确定。当协同程序不消耗CPU时间也不更新任何局限于特定线程的共享数据(如UI)时,无限制调度程序是合适的。

另一方面, coroutineContext 属性(在任何协同程序中可用)是对此特定协同程序的上下文的引用。这样,可以继承父上下文。特别是runBlocking协同程序的默认调度程序仅限于调用程序线程,因此继承它具有通过可预测的FIFO调度将执行限制在此线程的效果。

执行者本身执行的上下文无关紧要(正确性)。一个actor是一个协程,一个协同程序按顺序执行,因此将状态限制到特定协程可以解决共享可变状态的问题。实际上,演员可以修改自己的私有状态,但只能通过消息相互影响(避免任何锁定)。

Actor比在负载下锁定更有效,因为在这种情况下它总是有工作要做,而且根本不需要切换到不同的上下文。

注意,actor协程构建器是产品协同程序构建器的双重构件。一个actor与它接收消息的频道相关联,而一个制作者与它发送元素的频道相关联。

选择表达式可以同时等待多个挂起函数,并选择 第一个可用的挂起函数。

让我们有两个字符串生成器:fizz和buzz。该fizz生产“菲斯”串每300毫秒:

而buzz产品“Buzz!” 字符串每500毫秒:

使用接收暂停功能,我们可以接收任一从一个通道或其他。但select表达式允许我们同时使用其 onReceive子句从两者接收:

所述的onReceive条款select当信道被关闭引起相应失败 select抛出异常。我们可以使用onReceiveOrNull子句在关闭通道时执行特定操作。以下示例还显示该select表达式返回其所选子句的结果:

让我们使用它a产生“Hello”字符串四次的频道b和产生“世界”四次的频道:

这段代码的结果非常有趣,所以我们将在模式细节中分析它:

首先,select是偏向于第一条。当可以同时选择多个子句时,其中的第一个子句将被选中。在这里,两个通道都在不断地产生字符串,因此a作为select中的第一个子句的channel获胜。但是,因为我们使用的是无缓冲通道,所以a它的发送调用会不时地暂停,并且也有机会b发送。

第二个观察结果是,当通道已经关闭时,会立即选择onReceiveOrNull。

选择表达式具有onSend子句,可以与选择的偏见性结合使用。

让我们编写一个整数生成器的示例,side当主要通道上的消费者无法跟上它时,它会将其值发送到通道:

消费者将会非常缓慢,需要250毫秒才能处理每个号码:

那么让我们看看会发生什么:

可以使用onAwait子句选择延迟值。让我们从一个异步函数开始,该函数在随机延迟后返回一个延迟字符串值:

让我们随机延迟开始十几个。

现在,主函数等待第一个函数完成并计算仍处于活动状态的延迟值的数量。注意,我们在这里使用的select表达式是Kotlin DSL,因此我们可以使用任意代码为它提供子句。在这种情况下,我们遍历一个延迟值列表,onAwait为每个延迟值提供子句。

让我们编写一个使用延迟字符串值通道的通道生成器函数,等待每个接收的延迟值,但只有在下一个延迟值结束或通道关闭之前。这个例子将onReceiveOrNull和onAwait子句放在一起 select:

为了测试它,我们将使用一个简单的异步函数,它在指定的时间后解析为指定的字符串:

main函数只是启动一个协程来打印结果switchMapDeferreds并向它发送一些测试数据:

}

(从下列各题四个备选答案中选出一个正确答案,并将其代号写在答题

纸相应位置处。答案错选或未选者,该题不得分。

(判断以下论述的正误,

认为正确的就在答题相应位置划

}

在阅读了《Java并发编程的艺术》这本书后, 总结思考, 发表了这个文章, 其本质属于一个关于并发的笔记, 为了面试的知识总结。 正文所有内容版权大部分属于此书的作者, 感谢老师的书, 让学生受益匪浅, 获益良多
也有引用的有些博主写的文章的部分内容, 版权属于其作者

  • 指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态
  • 指用户线程与垃圾收集线程同时执行(但不一定是并行的,可能会交替执行),用户程序在继续运行。而垃圾收集程序运行在另一个CPU上

  • CPU通过时间片分配算法来循环执行任务,当前任务执行一个时间片后会切换到下一个任务
    但是,在切换前会保存上一个任务的状态,以便下次切换回这个任务时,可以再加载这个任务的状态
    所以任务从保存到再加载的过程就是一次上下文切换
    上下文切换会影响多线程的执行速度, 以下介绍4种解决方式
  1. 多线程竞争锁时,会引起上下文切换,所以多线程处理数据时,可以用一些办法来避免使用锁,如将数据的ID按照Hash算法取模分段,不同的线程处理不同段的数据
  2. Java的Atomic包使用CAS算法来更新数据,而不需要加锁
  3. 避免创建不需要的线程,比如任务很少,但是创建了很多线程来处理,这
    样会造成大量线程都处于等待状态
  4. 在单线程里实现多任务的调度,并在单线程里维持多个任务间的切换
  • 锁是个非常有用的工具,运用场景非常多,因为它使用起来非简单,而且易于理解
    但同时它也会带来一些困扰,那就是可能会引起死锁,一旦产生死锁,就会造成系统功能不可用
  • 介绍避免死锁的几个常见方法
  1. 避免一个线程同时获取多个锁
  2. 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源
  3. 尝试使用定时锁,使用parable 接口。因此该队列中元素的排序就取决于你自己的 Comparable 实现。 是一个特殊的队列,它的内部同时只能够容纳单个元素。如果该队列已有一元素的话,试图向队列中插入一个新元素的线程将会阻塞,直到另一个线程将该元素从队列中抽走。同样,如果该队列为空,试图向队列中抽取一个元素的线程将会阻塞,直到另一个线程向队列中插入了一条新的元素。据此,把这个类称作一个队列显然是夸大其词了。它更多像是一个汇合点
  • 其实阻塞队列实现阻塞同步的方式很简单,使用的就是是lock锁的多条件(condition)阻塞控制。使用BlockingQueue封装了根据条件阻塞线程的过程,而我们就不用关心繁琐的await/signal操作了
  • 思想:大任务拆成小任务,汇总小任务的结果

  • 在Atomic包里一共有13个类,四种原子更新方式,分别是
    原子更新基本类型,原子更新数组,原子更新引用和原子更新字段
    Atomic包里的类基本都是使用Unsafe实现的包装类。依赖的都是CAS操作
  • 用于通过原子的方式更新基本类型,Atomic包提供了以下三个类:
  • 通过原子的方式更新数组里的某个元素,Atomic包提供了以下3个类:
  • 原子更新基本类型的AtomicInteger,只能更新一个变量,如果要原子的更新多个变量,就需要使用这个原子更新引用类型提供的类。Atomic包提供了以下三个类:
  • 如果我们只需要某个类里的某个字段,那么就需要使用原子更新字段类,Atomic包提供了以下三个类:
  • AtomicStampedReference:原子更新带有版本号的引用类型。该类将整数值与引用关联起来,可用于原子的更数据和数据的版本号,可以解决使用CAS进行原子更新时,可能出现的ABA问题。
  • 多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力
  • 线程池作用就是限制系统中执行线程的数量
    • 根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果;少了浪费了系统资源,多了造成系统拥挤效率不高。用线程池控制线程数量,其他线程排队等候。一个任务执行完毕,再从队列的中取最前面的任务开始执行。若队列中没有等待进程,线程池的这一资源处于等待。当一个新任务需要运行时,如果线程池中有等待的工作线程,就可以开始运行了;否则进入等待队列。
    1. 减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
    2. 可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。
    • Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是ExecutorService
    • Java里面线程池的顶级接口是Executor,但是严格意义上讲Executor并不是一个线程池,而只是一个执行线程的工具。真正的线程池接口是ExecutorService
      • 能和Timer/TimerTask类似,解决那些需要任务重复执行的问题。
  • 要配置一个线程池是比较复杂的,尤其是对于线程池的原理不是很清楚的情况下,很有可能配置的线程池不是较优的,因此在Executors类里面提供了一些静态工厂,生成一些常用的线程池。
    • 创建一个单线程的线程池。这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
    • 创建固定大小的线程池。每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
    • 创建一个可缓存的线程池。如果线程池的大小超过了处理任务所需要的线程,
      那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。
    • 创建一个大小无限的线程池。此线程池支持定时以及周期性执行任务的需求
    • 固定数量的线程池,没提交一个任务就是一个线程,直到达到线程池的最大数量,然后后面进入等待队列直到前面的任务完成才继续执行
    • 单个线程的线程池,即线程池中每次只有一个线程工作,单线程串行执行任务
    • 可缓存线程池, 当线程池大小超过了处理任务所需的线程,那么就会回收部分空闲(一般是60秒无执行)的线程 ,当有任务来时,又智能的添加新线程来执行
    • 大小无限制的线程池,支持定时和周期性的执行线程
}

我要回帖

更多关于 html爱心代码 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信