`
yesjavame
  • 浏览: 687841 次
  • 性别: Icon_minigender_2
  • 来自: 杭州
文章分类
社区版块
存档分类
最新评论

Java 多线程编程中的设计模式 开篇

阅读更多

<放水开始>
什么是模式?有太多的介绍模式的书,似乎用不着我再来给模式下一个定义.正如什么是道?
除了老子有权解释,其他任何试图向别人解释什么是道的人,其实根本就不懂道!更别说什么
初论,再论,三论,x论,末流之论也.你不论说明你还懂一些,如果你论,说明你根本就不懂道.
因为老子已经说得非常清楚:道可道,非常道!

那么我们是否已经陷入了不可知论?非也.不可道之道,是真正的大道.大道虽然无形,但每个人对它
的感受是有形有,我们在向别人说明时其实说的是你"自己对道的感觉",无论你如何论道你的感觉都
不代表真正的"道".

因为每个人的感觉不同,所以尽管有很多人介绍过模式,我从中学习了很多我不知道的知识,但我有
我的感受,我也有其它人不知道的知识,或者张狂一点说比某些人高明一些的知识,所以我要写我自
己的模式系列.以我的观点而言:
<放水暂停>


模式就是在某种特定环境中,经常多次发生的问题的通用解决方案.

环境,或说背景,用Java术语说是Context.
问题里面还包含可以解决问题的外力条件(force),多个外力条件常常表现为"鱼与熊掌"的关系.

尽管目前真正介绍模式的书并不多,但在可见的介绍模式的书中,可以看到多数就是一本
模式词典.设计模式中真正的知识在于[模式语言].

模式语言是模式的集合,集合的意思是集而合之,不是聚合.
把多个相关的,相互作用的模式集而合之,并清楚地描述它们之间的关系.就是模式语言.

模式是对某一个或某部分问题的通用解决方法.而模式语言是对某一领域中多个相关的问题集的解决
方案的集成.这不仅仅是程序设计和软件开发过程的问题,任何领域中,能够描述出原则,主次,方法,
技巧的抽象集合都是模式语言.

如果你还要继续向下看,或者你还有兴趣看我的放水文章.那么请记住这句话:

[学会模式和自如地应用模式进行设计是完全不同的两回事],keep it in your mind!

<放水继续>
记得在清华举行的中国软件业协会JAVA分成立大会上,我向Java程序员推荐过两本哲学的书.
<<全息论>>,<<系统与层次>>.现在我再多加一本中科院哲学所刘长林先生的<<内经的哲学和中医学的方法>>

宏观与微观:
很多时候,我在与一些朋友讨论一些"细节"的内容时,总有些人问"讨论这种问题对解决软件
企业的实际问题有何意义?",不客气地说,这些无知的话题决定了提问者本身就不可能有真正的解决
"企业级应用问题"的能力.

作为一个建筑设计师,他自己当然不会去干抹水泥,码砖头这样的活.但他要比这些码砖头,抹水泥的
小工更清楚每块砖头的强度,年限,每种水泥的凝固时间,粘度等细节参数.否则你的设计再好也只
能建一个豆腐渣工程.

作为一个软件系统架构师,如果不懂你的coder在项目中使用的细节技术,重要组件,重要API实现
你如何保证你的项目的性能和可靠性?难道真的靠默念口诀就能获得一种神奇的效果?

有人说"一个人一生的时间的有限的,把太多的时候花在这些细节上,我就没有更多的时间掌握好些最实用的如structs,spring,hb等",那么我告诉你,如果你不了解最基础的东西,你学三个月structs,spring,hb,我只要一周会

比你掌握更深入,即使Upload这样的小工具,明知道smartUpload的Bug巨多,不好用,有几个人能自动手写出来?当我第一次使用时我就花了40分钟自己写了一个公开在bea论坛上经几年大家的试用还未发现bug,这就是"微观"的重要性.

"设计时脑子里只的模型,对象,实现时调试到汇编!".

这是我一贯以求并一直坚持的架构原则.对于一个架构师而言,与程序设计相关的知识没有主要和
次要之分,从单片机到汇编到到软件工程思想.都是你应该掌握的.听过撒贝宁讲背书的事,因为他老是不上课,
所以复习时不知道哪里是老师划过的重点.好,那我把整本书作为重点背下来!

如何应用模式和模式语言?在你掌握了模式与模式语言的情况下,有三种应用水平:
一是在学会了很多模式后在设计时总是想用上一些模式为了显示我懂设计模式,如果这样你还不
如一点不懂设计模式.Just in time(需要的时候才去做)!
二是在遇到类似问题时能熟悉应用现有模式,这是绝对大多数如我这类中人之资水平能做的事.总之
"不会过日看邻居"一般是不会错的.
三是一种因为掌握了很多模式的基础上,经过不断实践在需要解决问题时没有现成的模式可用时自己
抽象出设计模式.相信自己,你可以做到!

所谓大师能做到举手投足之间都有惊世骇俗之举.嘻笑怒骂之间也能成黄钟大吕之作.而我们常人,
在平凡的生活中总会能悟出一点特别的东西,只不过不如大师那样来得容易.

我把要放水的内容在首节放完,下面就一心一意讲我的设计模式知识.本系列绝不是模式词典.
<放水结束>

这篇文章算是开场,就不连着介绍第一个模式了.但和它相关的是比任何模式更重要的一篇文章.转
贴过来,这才是模式的境界:(注意不是看懂它.而是能做到才是真正的设计模式境界)

A C# Bedtime Story
The following is an excerpt from Windows Forms 2.0 Programming, Chris Sells & Michael Weinhardt, Addison-Wesley, 2006. It's been updated from the original version for C# 2.0.

Once upon a time, in a strange land south of here, there was a worker named Peter. He was a diligent worker who would readily accept requests from his boss. However, his boss was a mean, untrusting man who insisted on steady progress reports. Since Peter did not want his boss standing in his office looking over his shoulder, Peter promised to notify his boss whenever his work progressed. Peter implemented this promise by periodically calling his boss back via a typed reference like so:

class Worker {
Boss boss;

public void Advise(Boss boss) {
this.boss = boss;
}

public void DoWork() {
Console.WriteLine("Worker: work started");
if( this.boss != null ) this.boss.WorkStarted();

Console.WriteLine("Worker: work progressing");
if( this.boss != null ) this.boss.WorkProgressing();

Console.WriteLine("Worker: work completed");
if( this.boss != null ) {
int grade = this.boss.WorkCompleted();
Console.WriteLine("Worker grade= {0}", grade);
}
}
}

class Boss {
public void WorkStarted() {
// Boss doesn't care
}
public void WorkProgressing() {
// Boss doesn't care
}
public int WorkCompleted() {
Console.WriteLine("It's about time!");
return 2; // out of 10
}
}

class Universe {
static void Main() {
Worker peter = new Worker();
Boss boss = new Boss();
peter.Advise(boss);
peter.DoWork();

Console.WriteLine("Main: worker completed work");
Console.ReadLine();
}
}

Interfaces
Now Peter was a special person. Not only was he able to put up with his mean-spirited boss, but he also had a deep connection with the universe around him. So much so that he felt that the universe was interested in his progress. Unfortunately, there was no way for Peter to advise the Universe of his progress unless he added a special Advise method and special callbacks just for the Universe, in addition to keeping his boss informed. What Peter really wanted to do was to separate the list of potential notifications from the implementation of those notification methods. And so he decided to split the methods into an interface:

interface IWorkerEvents {
void WorkStarted();
void WorkProgressing();
int WorkCompleted();
}

class Worker {
IWorkerEvents events;

public void Advise(IWorkerEvents events) {
this.events = events;
}

public void DoWork() {
Console.WriteLine("Worker: work started");
if( this.events != null ) this.events.WorkStarted();

Console.WriteLine("Worker: work progressing");
if( this.events != null ) this.events.WorkProgressing();

Console.WriteLine("Worker: work completed");
if( this.events!= null ) {
int grade = this.events.WorkCompleted();
Console.WriteLine("Worker grade= {0}", grade);
}
}
}

class Boss : IWorkerEvents {
public void WorkStarted() {
// Boss doesn't care
}
public void WorkProgressing() {
// Boss doesn't care
}
public int WorkCompleted() {
Console.WriteLine("It's about time!");
return 3; // out of 10
}
}

Delegates
Unfortunately, Peter was so busy talking his boss into implementing this interface that he didn't get around to notifying the Universe, but he knew he would soon. At least he'd abstracted the reference of his boss far away from him so that others who implemented the IWorkerEvents interface could be notified of his work progress.

Still, his boss complained bitterly. "Peter!" his boss fumed. "Why are you bothering to notify me when you start your work or when your work is progressing?!? I don't care about those events. Not only do you force me to implement those methods, but you're wasting valuable work time waiting for me to return from the event, which is further expanded when I am far away! Can't you figure out a way to stop bothering me?"

And so, Peter decided that while interfaces were useful for many things, when it came to events, their granularity was not fine enough. He wished to be able to notify interested parties only of the events that matched their hearts' desires. So, he decided to break the methods out of the interface into separate delegate functions, each of which acted like a little tiny interface of one method each:

delegate void WorkStarted();
delegate void WorkProgressing();
delegate int WorkCompleted();

class Worker {
public WorkStarted Started;
public WorkProgressing Progressing;
public WorkCompleted Completed;

public void DoWork() {
Console.WriteLine("Worker: work started");
if( this.Started != null ) this.Started();

Console.WriteLine("Worker: work progressing");
if( this.Progressing != null ) this.Progressing();

Console.WriteLine("Worker: work completed");
if( this.Completed != null ) {
int grade = this.Completed();
Console.WriteLine("Worker grade= {0}", grade);
}
}
}

class Boss {
public int WorkCompleted() {
Console.WriteLine("It's about time!");
return 4; // out of 10
}
}

class Universe {
static void Main() {
Worker peter = new Worker();
Boss boss = new Boss();

// NOTE: We've replaced the Advise method with the assignment operation
peter.Completed = new WorkCompleted(boss.WorkCompleted);
peter.DoWork();

Console.WriteLine("Main: worker completed work");
Console.ReadLine();
}
}

And, because Peter was under so much pressure, he decided to advantage of the shorthand notation for assigning delegates provided by C# 2.0:

class Universe {
static void Main() {
...
peter.Completed = boss.WorkCompleted;
...
}
}

Static Listeners
Delegates accomplished the goal of not bothering his boss with events that he didn't want, but still Peter had not managed to get the universe on his list of listeners. Since the universe is an all-encompassing entity, it didn't seem right to hook delegates to instance members (imagine how many resources multiple instances of the universe would need...). Instead, Peter need to hook delegates to static members, which delegates support fully:

class Universe {
static void WorkerStartedWork() {
Console.WriteLine("Universe notices worker starting work");
}

static int WorkerCompletedWork() {
Console.WriteLine("Universe pleased with worker's work");
return 7;
}

static void Main() {
Worker peter = new Worker();
Boss boss = new Boss();

peter.Completed = boss.WorkCompleted;
peter.Started = WorkerStartedWork;
peter.Completed = WorkerCompletedWork; // Oops!
peter.DoWork();

Console.WriteLine("Main: worker completed work");
Console.ReadLine();
}
}

Events
Unfortunately, the Universe being very busy and unaccustomed to paying attention to individuals, has managed to replace Peter's boss's delegate with its own. This is an unintended side effect of making the delegate fields public in Peter's Worker class. Likewise, if Peter's boss gets impatient, he can decide to fire Peter's delegates himself (which is just the kind of rude thing that Peter's boss was apt to do):

// Peter's boss taking matters into his own hands
if( peter.Completed != null ) peter.Completed();

Peter wants to make sure that neither of these can happens. He realizes he needs to add registration and unregistration functions for each delegate so that listeners can add or remove themselves, but can't clear the entire list or fire Peter's events. Instead of implementing these functions himself, Peter uses the event keyword to make the C# compiler build these methods for him:

class Worker {
public event WorkStarted Started;
public event WorkProgressing Progressing;
public event WorkCompleted Completed;
...
}

Peter knows that the event keyword erects a property around a delegate, only allowing clients to add or remove themselves (using the += and -= operators in C#), forcing his boss and the universe to play nicely:

class Universe {
...
static void Main() {
Worker peter = new Worker();
Boss boss = new Boss();

peter.Completed = boss.WorkCompleted; // ERR!
peter.Completed += boss.WorkCompleted; // OK
peter.Started += Universe.WorkerStartedWork; // OK
peter.Completed += Universe.WorkerCompletedWork; // OK

peter.DoWork();

Console.WriteLine("Main: worker completed work");
Console.ReadLine();
}
}

Harvesting All Results
At this point, Peter breathes a sigh of relief. He has managed to satisfy the requirements of all his listeners without having to be closely coupled with the specific implementations. However, he notices that while both his boss and the universe provide grades of his work that he's only receiving one of the grades. In the face of multiple listeners, he'd really like to harvest all of their results. So, he reaches into his delegate and pulls out the list of listeners so that he can call each of them manually:

class Worker {
...
public void DoWork() {
...
Console.WriteLine("Worker: work completed");

if( this.Completed != null ) {
foreach( WorkCompleted wc in this.Completed.GetInvocationList() ) {
int grade = wc();
Console.WriteLine("Worker grade= {0}", grade);
}
}
}
}

public void DoWork() {
...
Console.WriteLine("Worker: work completed");
if( completed != null ) {
foreach( WorkCompleted wc in completed.GetInvocationList() ) {
int grade = wc();
Console.WriteLine("Worker grade= " + grade);
}
}
}

Asynchronous Notification: Fire & Forget
In the meantime, his boss and the universe have been distracted with other things, which meant that the time it takes them to grade Peter's work is greatly expanded:

class Boss {
public int WorkCompleted() {
System.Threading.Thread.Sleep(5000);
Console.WriteLine("Better...");
return 4; // out of 10
}
}

class Universe {
...
static int WorkerCompletedWork() {
System.Threading.Thread.Sleep(1000000);
Console.WriteLine("Universe pleased with worker's work");
return 7;
}
...
}

Unfortunately, since Peter is notifying each listener one at a time, waiting for each to grade him, these notifications now take up quite a bit of his time when he should be working. So, he decides to forget the grade and just fire the event asynchronously:

class Worker {
...
public void DoWork() {
...
Console.WriteLine("Worker: work completed");
if( this.Completed != null ) {
foreach( WorkCompleted wc in this.Completed.GetInvocationList() ) {
wc.BeginInvoke(null, null); // EndInvoke call required by .NET
}
}
}
}

Asynchronous Notification: Polling
The call to BeginInvoke allows Peter to notify the listeners while letting Peter get back to work immediately, letting the process thread pool invoke the delegate. Over time, however, Peter finds that he misses the feedback on his work. He knows that he does a good job and appreciates the praise of the universe as a whole (if not his boss specifically). Plus, hes afraid hes leaking .NET resources acquired by calling BeginInvoke without calling the corresponding EndInvoke method, so, he fires the event asynchronously, but polls periodically, looking for the grade to be available:

class Worker {
...
public void DoWork() {
...
Console.WriteLine("Worker: work completed");
if( this.Completed != null ) {
foreach( WorkCompleted wc in this.Completed.GetInvocationList() ) {
IAsyncResult result = wc.BeginInvoke(null, null);
while( !result.IsCompleted ) System.Threading.Thread.Sleep(1);
int grade = wc.EndInvoke(result);
Console.WriteLine("Worker grade= {0}", grade);
}
}
}
}

Asynchronous Notification: Delegates
Unfortunately, Peter is back to what he wanted his boss to avoid with him in the beginning, i.e. looking over the shoulder of the entity doing the work. So, he decides to employ his own delegate as a means of notification when the asynchronous work has completed, allowing him to get back to work immediately, but still be notified when his work has been graded:

class Worker {
...
public void DoWork() {
...
Console.WriteLine("Worker: work completed");
if( this.Completed != null ) {
foreach( WorkCompleted wc in this.Completed.GetInvocationList() ) {
wc.BeginInvoke(this.WorkGraded, wc);
}
}
}

void WorkGraded(IAsyncResult result) {
WorkCompleted wc = (WorkCompleted)result.AsyncState;
int grade = wc.EndInvoke(result);
Console.WriteLine("Worker grade= {0}" + grade);
}
}

Anonymous Delegates
At this point, Peter is using delegates to notify interested parties in the process of his work and using delegates to get notified when grades are available on the work hes completed. The delegates provided by his boss and the universe are provided by separate entities, so it makes sense that they are encapsulated in methods on those entities. However, in the case of the WorkGraded method, theres really no good reason for this to be a separate method except the syntactic requirements of C# 1.0. As of C# 2.0, Peter can drop the code required to handle the processing of his work grade into an anonymous delegate:

class Worker {
...
public void DoWork() {
...
Console.WriteLine("Worker: work completed");
if( this.Completed != null ) {
foreach( WorkCompleted wc in this.Completed.GetInvocationList() ) {
wc.BeginInvoke(delegate(IAsyncResult result) {
WorkCompleted wc2 = (WorkCompleted)result.AsyncState;
int grade = wc2.EndInvoke(result);
Console.WriteLine("Worker grade= {0}", grade);
},
wc);
}
}
}
}

Here, instead of passing in the name of a method to call when his work has been graded, hes passing in the body of the method itself as designated with a different use of the delegate keyword to create a method with no name (and therefore anonymous). The body of the method is fundamentally the same in that Peter still passes the WorkCompleted delegate as a parameter to BeginInvoke and then pulls it out of AsyncState for use in extracting the result. However, one of the benefits of anonymous delegates that Peter knows is that he can make use of the variables in the surrounding context from within the anonymous delegate body, causing him to rewrite his code thusly:

class Worker {
...
public void DoWork() {
...
Console.WriteLine("Worker: work completed");
if( this.Completed != null ) {
foreach( WorkCompleted wc in this.Completed.GetInvocationList() ) {
wc.BeginInvoke(delegate(IAsyncResult result) {
// Use wc variable from surrounding context (ERR!)
int grade = wc.EndInvoke(result);
Console.WriteLine("Worker grade= {0}", grade);
},
null);
}
}
}
}

This code compiles just fine, but when its run, it will cause the following exception to be thrown:

System.InvalidOperationException:
The IAsyncResult object provided does not match this delegate.
The problem is that while the wc variable is allowed to be used in the anonymous delegate, its still being used by the for-each statement. As soon as the asynchronous invocation begins, the wc variable changes and the delegate used to start things (wc) no longer matches the async result passed as an argument to the anonymous delegate. Peter slaps his head and creates a hybrid solution:

class Worker {
...
public void DoWork() {
...
Console.WriteLine("Worker: work completed");
if( this.Completed != null ) {
foreach( WorkCompleted wc in this.Completed.GetInvocationList() ) {
// Create an unchanging variable referencing the current delegate
WorkCompleted wc2 = wc;
wc.BeginInvoke(delegate(IAsyncResult result) {
// Use wc2 variable from surrounding context
int grade = wc2.EndInvoke(result);
Console.WriteLine("Worker grade= {0}", grade);
},
null);
}
}
}
}

public void DoWork() {
...
Console.WriteLine("Worker: work completed");
if( completed != null ) {
foreach( WorkCompleted wc in completed.GetInvocationList() ) {
wc.BeginInvoke(new AsyncCallback(WorkGraded), wc);
}
}
}

void WorkGraded(IAsyncResult res) {
WorkCompleted wc = (WorkCompleted)res.AsyncState;
int grade = wc.EndInvoke(res);
Console.WriteLine("Worker grade= " + grade);
}

Happiness in the Universe
Peter, his boss and the universe are finally satisfied. Peter's boss and the universe are allowed to be notified of the events that interest them, reducing the burden of implementation and the cost of unnecessary round-trips. Peter can notify them each, ignoring how long it takes them to return from their target methods, while still getting his results asynchronously and handling them using anonymous delegates, resulting in the following complete solution:

delegate void WorkStarted();
delegate void WorkProgressing();
delegate int WorkCompleted();

class Worker {
public event WorkStarted Started;
public event WorkProgressing Progressing;
public event WorkCompleted Completed;

public void DoWork() {
Console.WriteLine("Worker: work started");
if( this.Started != null )
this.Started();

Console.WriteLine("Worker: work progressing");
if( this.Progressing != null )
this.Progressing();

Console.WriteLine("Worker: work completed");
if( this.Completed != null ) {
foreach( WorkCompleted wc in this.Completed.GetInvocationList() ) {
WorkCompleted wc2 = wc;
wc.BeginInvoke(delegate(IAsyncResult result) {
int grade = wc2.EndInvoke(result);
Console.WriteLine("Worker grade= {0}", grade);
},
null);
}
}
}
}

class Boss {
public int WorkCompleted() {
System.Threading.Thread.Sleep(3000);
Console.WriteLine("Better...");
return 5; // out of 10
}
}

class Universe {
static void WorkerStartedWork() {
Console.WriteLine("Universe notices worker starting work");
}

static int WorkerCompletedWork() {
System.Threading.Thread.Sleep(4000);
Console.WriteLine("Universe pleased with worker's work");
return 7;
}

static void Main() {
Worker peter = new Worker();
Boss boss = new Boss();
peter.Completed += boss.WorkCompleted;
peter.Started += Universe.WorkerStartedWork;
peter.Completed += Universe.WorkerCompletedWork;
peter.DoWork();

Console.WriteLine("Main: worker completed work");
}
}

Peter knows that getting results asynchronously comes with issues, because as soon as he fires events asynchronously, the target methods are likely to be executed on another thread, as is Peter's notification of when the target method has completed. However, Peter is good friends with Mike, who is very familiar with threading issues and can provide guidance in that area.

And they all lived happily every after.

The end.

分享到:
评论

相关推荐

    Java并发编程的艺术

    第六章专注于Java中的并发容器,这些容器被设计用来支持多线程环境下的高效数据访问。本章详细分析了ConcurrentHashMap、CopyOnWriteArrayList等容器的内部实现机制,揭示了它们如何在保证线程安全的同时,还能提供...

    Java就业班体系结构文档,Java核心知识,提升Java开发技能、理解Java核心技术及应用场景

    此外,本资源还提供了有关数据库、前端开发、JavaEE、分布式系统以及设计模式、多线程与高并发等内容的深入讲解,帮助读者扩展Java开发的应用领域。 请注意,《Java就业班体系结构.pdf》是一份高质量的学习资料,...

    《thingking in java》三四版

    书中详细介绍了Java的多线程编程,包括Thread类、Runnable接口、同步机制(如synchronized关键字、wait/notify机制)、线程池以及并发工具类。这部分内容对于理解和编写高效的并发程序至关重要。 第五部分:输入/...

    01_黑马程序员_张孝祥_Java基础加强_课程价值与目标介绍.zip

    在【标签】"Java加强"中,我们可以推断这门课程不仅覆盖了Java的基础知识,还可能涉及了一些进阶主题,比如面向对象编程的深入理解、异常处理、多线程、集合框架的高级用法、IO流和NIO、网络编程等,以提升学员对...

    JAVE EE 企业级开发之从零开始学JAVA

    课程进一步推进至JAVA SE的高级应用领域,如多线程编程,redking解释了线程生命周期、同步机制和线程安全问题,这些都是开发高性能、高并发系统的基础。接着,IO操作、网络编程和数据库编程被详细介绍,这些技能是...

    Concurrent+Programming+in+Java+-+Design+Principles+and+Patterns,+Second+Edition_

    本章节作为本书的开篇,旨在介绍如何在Java编程语言中思考、设计和实现并发程序。大部分内容假设读者已经是一位有经验的对象导向编程(OO)开发者,但对于并发编程的了解不多。同时,对于那些在其他语言中有并发编程...

    S2~Y2转换课程(Java方向)(课件1)

    【标题】"S2~Y2转换课程(Java方向)(课件1)" 指的是一门...通过这些基础知识的学习,学员将能够编写简单的Java程序,并为后续的Java进阶课程做好准备,例如深入研究多线程、网络编程、数据库连接、设计模式等内容。

    The Secrets of Low Latency Java Applications Simon Ritter

    多线程模型允许每个对象具有一个单独的锁,支持程序级锁定和部分自动化解锁,提高了代码的安全性和效率。 ### 应用堆栈与硬件影响 应用堆栈方面,文章提及了Java应用、应用服务器、JVM、操作系统以及硬件(如CPU、...

    59e95a4689eeb92f380f4ab2_202109_8dec713c-1467-11ec-8eed-00163e0396a1_java 2实用教程第6版实验指导模板代码(2021-4-1版本).rar

    《Java 2 实用教程第6版实验指导模板代码》是针对Java编程初学者和进阶者的一份宝贵资源,包含多个章节的实践代码示例。这个2021年4月1日版本的压缩包提供了丰富的编程练习,旨在帮助学习者深入理解和应用Java语言的...

    iOS应用架构谈 开篇 - Casa Taloyum1

    本文将从“iOS应用架构谈 开篇 - Casa Taloyum1”出发,探讨iOS应用程序的常见架构模式以及如何构建高效、可复用的代码结构。 首先,iOS应用的视图层(View Layer)是用户界面的直接呈现部分,包括UIControls、...

    Learn JavaFX 8.pdf

    17. **Concurrency in JavaFX**: 讲述JavaFX的并发模型,它支持多线程编程,以实现高效率的应用程序。 18. **Playing Audios and Videos**: 描述了在JavaFX应用程序中嵌入和播放音频及视频的方法。 19. **...

    Apress.Accelerated.C#.2008.pdf

    - **介绍**:这一章探讨了C#中的多线程编程。 - **重点内容**: - 多线程的基本原理,包括线程的创建和同步机制。 - 如何使用Task并行库(TPL)来简化多线程编程。 - 并发集合和异步编程模式的使用技巧。 ### 13. ...

    jsp入门教程

    - **线程模型**:探讨JSP页面的多线程处理机制。 - **在JSP中定义类变量**:了解如何在JSP页面中定义和使用类变量。 - **JSP九大默认对象**:介绍JSP提供的九个内置对象及其用途。 #### 第15章 分页 - **数据库分页...

    Learn JavaFX 8

    JavaFX 支持多线程编程。本章讨论了如何在 JavaFX 中正确地处理并发问题。 ##### 第 28 章:播放音频和视频 多媒体支持是现代应用程序不可或缺的一部分。本章介绍了 JavaFX 中的音频和视频播放功能。 ##### 第 29 ...

Global site tag (gtag.js) - Google Analytics