`
bolutes
  • 浏览: 869329 次
文章分类
社区版块
存档分类
最新评论

Java多线程设计模式详解学习笔记——Introduction1 Java语言的线程

 
阅读更多

GUI应用程序

几乎所有的GUI应用程序都会用多线程。举例来说加入现在有人在用word编辑一个比较大的文本文件刚刚才做过单字“查找”操作,当word进行查找时,屏幕上会出现“停止查找按钮”,用户可以随时停止查找。这个功能其实就用到了多线程。

(1)执行查找

(2)显示按钮,若按钮按下则停止查找

这两个操作分别交给不同的线程进行。这样一来执行线程(1)的线程可以专心查找,执行(2)的线程也可专心在GUI操作上,程序就会变得比较简单。

比较花费时间的I/O操作

多个客户端

基本上网络上的服务器必须同时处理一个以上的客户端,不过,一定要在服务器这边的程序设计加入一个以上客户端的概念的话,程序会变得更复杂。此时,不妨准备一个当有客户端连接到服务器的时候,会自动出来迎接这个客户点的线程,这样一来,服务器的程序就可以设计成好像只服务一个客户端

并发与并行

当有一个以上的线程的线程来操作时,若计算机只有一个中央处理器,根本不可能进行一个以上的处理。

如果在有一个以上的中央处理器的计算机上跑程序,则线程的程序可能是并行(parallel)而非并发,就可以同时运行一个以上的处理。

线程的启动

“PrintThread的实例”和“线程本身”是两个不同的部分,即使建立了“PrintThread的实例”,也还没有启动线程,而且就算线程已经结束,PrintThread的实例也不会就这样消失不见。别忘了,在字符串输出结束之前,已经启动的两个线程还活着,一直要等到所有线程都已经结束,程序才会结束。当所有线程都结束,这个程序才会正式结束。

Thread类和Runnable接口

Thread类也实现了Runnable 接口,也有run()方法,只不过Thread类的run()方法的主体是空的没有执行任何部分。Thread类的run()方法通常是被子类覆盖(override)

Synchronized实例方法和Synchronized阻挡

假设现在有一个类型如下的synchronized实例方法

synchronized void method(){

}

在功能上和下面以synchronized阻挡为主的方法有异曲同工之妙。

void method(){

Synchronized(this){

}

}

换句话说synchronized方法是使用this锁去做线程的共享互斥。

Synchronized类方法和Synchronized阻挡

假设现在有一个类型如下的synchronized的类方法,synchronized类方法有限制同时只能让一个线程执行。这部分和synchronized实例方法一样,但是两者是有不同的。

Class Something{

static synchronized voidmethod(){

}

}

在功能上和下面以synchronized阻挡为主的方法有异曲同工之妙。

Class Something{

static void method(){

synchronized(Something.class){

}

}

}

换句话说synchronized的类方法是使用该类的类对象的锁去做线程的共享互斥。Something.class是对应Something类的java.lang.Class类的实例。

Wait方法——把线程放入wait set

使用wait方法时,线程便进入wait set,假设现在已经执行如下语句:obj.wait();

则目前的线程停止执行,进入实例obj的的wait set.这个操作成为:线程在obj上wait.

如果实例方法还有如下的语句时:wait();

则其意义同:this.wait();

故执行wait的线程就会进入this的wait set.此时就变成了在this上wait.

如欲执行wait()方法,线程需获取锁定(这是规则)。但是当线程进入wait set时,已经释放了该实例的锁定。


Notify方法——从wait set拿出线程

使用notify()(通知)方法时,可以从wait set拿出一个线程。

obj.nitify();则从wait set里的线程中挑出一个,唤醒这个线程。被唤醒的线程便退wait set



Notify后的线程

被notify唤醒的线程不是在notify后立即执行,因为在notify的那一刻,执行notify 的线程还握着锁定不放,所以其他线程无法获取该实例的锁定。

Notify如何选择线程

假设执行notify方法时,wait set里面正在执行的线程不止一个。规格并没有注明此时该选择哪一个线程。究竟是选择等待线程里面的第一个,随机选择或是另以其他方式选择,则以java处理系统而异。所以在写程序时,程序属性最好不要写成会因所选线程而有所变动。

notifyAll()方法——从wait set 拿出所有线程

使用notifyAll(通知全体)方法时,会将所有在waitset苦等的线程都拿出来。

obj.notifyAll()则会唤醒所有留在实例obj的wait set里的线程。

而notifyAll();则其意义同this.notifyAll();故这个语句所在方法的实例(this)的wait set里的线程会全部放出来。

跟wait方法和notify方法一样,线程必须要获取要调用实例的锁定,才能调用notifyAll方法。

被唤醒的线程便开始去获取刚才wait时释放掉的锁定,那么现在这个锁定现在是在谁的手中呢?没错,锁定就是在刚才执行notifyAll方法的程序手里,因此即使所有线程都退出了wait set,但他们仍然在去获得锁定的状态下,还是有阻挡。要等到刚才执行notifyAll方法的线程释放出锁定后,其中一名幸运儿才会实际执行。

要是没有锁定呢

若没有锁定的线程去调用wait,notify或notifyAll时,便会抛出异常java.lang.IllegalMonitorStateException.

调用notify方法还是notifyAll方法

Notify方法和notifyAll方法两者非常相似,到底该用哪一个?老实说,这个选择有点难。选择notify的话,因为要唤醒的线程比较少,程序处理速度当然要比notifyAll略胜一筹。但是选择notify时,若这部分程序处理的不好,可能会有程序挂掉的危险性,一般说来,选择notifyAll所写出来的程序代码要比选择notify可靠。除非你能确定程序员对程序代码的意义和能力限度一清二楚,否则选择notifyAll应该比较稳扎稳打



分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics