读书笔记-java网络编程-3线程-线程调度
来源:互联网 发布:java写入excel换行 编辑:程序博客网 时间:2024/06/07 13:55
4. 线程调度
4.1线程调度
java中10是最高优先级,0是最低优先级,默认的优先级5。
这与Unix优先级相反。
Windows只有7个优先级。
尽量不要设置过高的优先级否则会导致低优先级饥饿。
public final void setPriority(int newPriority)
使用这条语句来指定设置优先级。
4.2 抢占
主要有两种线程调度机制:
抢占式(preemptive):调度器确定正常地轮到某cpu时间时,会暂停这个线程,将cpu控制权交给另外的线程。
协作式(coorperative):等待线程自己暂停。
所有java虚拟机都保证在不同优先级之间使用抢占式的线程调度,在同样优先级之间偶尔会暂停其中一个线程,让下一个线程得到一些cpu时间。
在jvm虚拟机的机制下很难发现的,此外需要注意的是如果客户端的程序可能是协作式的,因此也有可能陷入饥饿状态。
通常来说一个线程有10中方式可以暂停或者指示它准备暂停:
1. 可以对IO阻塞
2. 可以对同步对象阻塞
3. 可以放弃
4. 可以休眠
5. 可以连接另一个对象
6. 可以等待另一个对象
7. 可以结束
8. 可以被更高优先级线程抢占
9. 可以被挂起
10. 可以被停止
最后两种方法以及不使用了,因为它会使得对象处于不一致的状况。
4.3 线程切换方式种类
4.3.1阻塞
当网络程序中的线程自动放弃CPU控制权,最常见的方式是对IO阻塞。同样进入一个同步方法
对于IO阻塞一般不会造成严重后果,要不获得所继续进行,要么抛出IOException异常。
或者代码块的时候也会阻塞。如果没有这个同步对象的锁,则会陷入阻塞。
有可能造成死锁的严重后果。
4.3.2 放弃
线程可以通过调用Thread.yield()静态方法来做到。将通知虚拟机,如果有另一个线程准备运行,可以运行该线程。但是有些虚拟机会忽视这个提示。
在放弃之前应该确保它与它关联的Runnable对象处于一致状态,因此在理想情况下,在线程放弃时不做任何同步。
public void run(){ while(true){ // Thread.yield(); }}
这使得其他有相同优先级的线程有机会运行
4.3.3 休眠
休眠与放弃类似,区别是不管有没有其他准备运行的线程,休眠的线程都会暂停。这样低优先级的线程会获得运行的机会。
缺点和线程一样,要避免在同步方法或块内让线程同步。
public static void sleep(long milliseconds) throws InterruptedExceptionpublic static void sleep(long milliseconds, int nanoseconds) throws InterruptedException
需要说明的是,这里的的秒速是不保证时间准确的,在实际编程的时候需要注意精度。
public void run(){ while(true){ if(!getPage("http://www.iboiblio.org")){ mailError("webmaster@ibiblio.org"); } try{ Tread.sleep(300000); }catch(InterruptedException ex){ break; } }}
有时候在时间到后没有办法立刻唤醒,因为JVM正在忙于其他的事情。同样也可能时间还没有到就中断了。通过
public void interrupt()
来完成。这就是线程和Thread对象之间的区别。线程在休眠,并不意外着其他醒着的线程不能处理这个线程相应的Thread对象。具体的说,另一个线程可以调用休眠Thread对象的interrupt()方法,会让休眠中的线程得到一个InterruptedExcetpion异常。并处理这个异常。
如果一个线程对IO操作阻塞,中断这个线程的效果很大程度上依赖于具体的平台。通常这将是一个什么都不做的操作。也就是说线程继续阻塞。如果你需要可中断的IO,应该认真考虑非阻塞的IO,而非流。
4.3.4 链接线程
java提供了join()方法,允许一个线程在运行之前等待其他线程结束。
public final void join() throws InterruptedExceptionpublic final void join(long milliseconds) throws InterruptedExceptionpublic final void join(long milliseconds, int nanoseconds) throws InterruptedException
这里把书上的例子 稍加改动变成了可以执行的版本如下:
package thread;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.security.DigestInputStream;import java.security.MessageDigest;import java.security.NoSuchAlgorithmException;public class ReturnDigest extends Thread { private String filename; private JoinDigestUserInterface callback; public ReturnDigest(String filename,JoinDigestUserInterface callback) { this.filename = filename; this.callback = callback; } public void run() { FileInputStream in; try { in = new FileInputStream(filename); MessageDigest sha = MessageDigest.getInstance("SHA-256"); DigestInputStream din = new DigestInputStream(in, sha); while (din.read()!=-1) ; din.close(); callback.setDigest(sha.digest()); } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); }catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}
package thread;import javax.xml.bind.DatatypeConverter;import org.junit.Test;public class JoinDigestUserInterface { private byte[] digest; public void setDigest(byte[] digest) { this.digest = digest; } @Test public void test(){ String[] list = new String[3]; list[0] = "E:\\tomcat\\webapps\\network\\bin\\thread\\test1.txt"; list[1] = "E:\\tomcat\\webapps\\network\\bin\\thread\\test2.txt"; list[2] = "E:\\tomcat\\webapps\\network\\bin\\thread\\test3.txt"; ReturnDigest[] digestThreads = new ReturnDigest[list.length]; for(int i = 0 ; i < 3 ; i++){ digestThreads[i] = new ReturnDigest(list[i],this); digestThreads[i].start(); } for(int i = 0 ; i < 3 ; i++){ try{ digestThreads[i].join(); // StringBuffer result = new StringBuffer(list[i]); result.append(":"); result.append(DatatypeConverter.printHexBinary(digest)); System.out.println(result); }catch(InterruptedException ex){ System.out.println("Thread Interrupt before completion"); } } }}
4.3.5 等待一个对象
线程可以等待一个它锁定的对象,在等待时,它会释放这个对象的锁并暂停,知道它得到其他线程的通知。
另一个线程以某种方式修改这个对象,通知等待对象的线程然后继续执行。
与连接不同的是,这里等待的是资源达到某种状态而不是等待线程结束。
public final void wait() throws InterruptedExceptionpublic final void wait(long milliseconds) throws InterruptedExceptionpublic final void wait(long milliseconds, int nanoseconds) throws InterruptedException
需要注意的是以上的方法是属于object类的。因此任何对象都可以调用上述的方法
调用时,它所属的线程会释放所等待对象的锁,但不会释放它所拥有的其他资源的锁。并进入休眠,线程也会休眠。直到发生下列3中情况之一:
- 时间到期
- 线程被中断
- 对象得到通知
超时时间(timeout)与sleep()和join()方法中的超时时间相同,即线程经过指定的一段时间后会唤醒。当时间到期,线程会从wait后开始执行,不过如果线程不能立即获得所等待对象的锁,它可能会继续阻塞
中断(Interruption)其他线程调用这个线程的interrupt方法。导致一个InterruptedException异常,并在捕获这个异常的catch内继续运行。不过在抛出异常钱线程要重新获得所等待对象的锁,因此调用interrupt方法后该线程可能仍然要阻塞一段时间。
通知(notification),在其他线程在这个线程所等待的对象上调用notify或者notifyall方法就会发生通知。这两个方法都在object中
public final void notify()public final void notifyall()
再通知一个对象之前,线程必须首先使用同步方法或块获得了对象的锁。notify()基本上随机地从等待这个对象的线程列表上选择一个线程,并将其唤醒。notifyall将唤醒所有线程
一旦等待线程得到通知,它就试图重新获得所等待对象的锁,如果成功就继续从wait后执行,如果失败就阻塞这个对象,直到获得锁。
这里少段程序
当多个线程希望等待同一个对象时,等待和通知会更为常见。
如果有多个线程在等待这个对象,首选notifyall,因为没有办法选择要通知哪个线程。
一般要将wait调用放在检测当前对象状态的循环中,不要假定因为线程得到了通知,对象现在就处于正确的状态。
这里少段程序
4.3.5 结束
当run方法返回时,线程将撤销,其他线程可以接管CPU。
在网络应用程序中,包装一个阻塞操作的线程往往会这样做,例如从服务器下载一个文件,这样应用程序的其他部分就不会被阻塞了。
- 读书笔记-java网络编程-3线程-线程调度
- 读书笔记-java网络编程-3线程-同步
- 读书笔记-java网络编程-3线程-java线程概述
- 读书笔记-java网络编程-3线程-从线程返回信息
- 读书笔记-java网络编程-3线程-线程池和Executor
- java线程编程读书笔记一(根据网络资料改编)
- Java网络编程 线程
- Java线程: 线程调度
- 并发编程3-线程调度
- 使用Executor代替手动的线程调度(java并发编程读书笔记五)
- Java网络编程—(3)线程上
- 《Windows核心编程》读书笔记七 线程调度,优先级和关联性
- JAVA 多线程编程 --线程的调度策略
- Java并发编程:线程生命周期和线程调度
- Java 线程第三版 第九章 Thread调度 读书笔记
- 《java多线程编程核心技术》读书笔记3:线程间的通信
- 《java并发编程》读书笔记--线程基础
- <Java 并发编程实践>读书笔记 --- 线程封闭
- Android第二天布局笔记
- Java一些基本知识
- 区块水平,垂直以及浮动后居中方式小结
- 【66】Scanner类用法详解
- HDU 1272 小希的迷宫(并查集,判断是否成环)
- 读书笔记-java网络编程-3线程-线程调度
- UIButton
- Android四大组件之 Activity(下)
- html+css 漂亮的登陆界面
- JavaWeb中如何使用filter清空网页缓存
- WIN10安装oracle11g客户端
- Android学习心得(19) --- short、byte、Hex、int、ULeb128类型转化Java源码
- Flex弹性盒模型初尝试
- Core Animation - 核心动画