1. Java的线程概念非常简单,目的是加强自己的内存管理。
2. 操作系统分时间片轮流运行每一个进程,而线程只是进一步发展了这一概念,把不同进程之间的切换改为在单个进程的若干不同功能模块之间进行切换。
3. 多线程程序中的任何线程都可以调用任何单线程程序中能够调用的一系列方法。eg. 让一个线程等待来自GUI的输入,让另一个线程处理接收的输入信息。
4. 线程允许程序一次执行多个动作。
5. 为什么采用多线程技术。(1)可以编写一个交互程序,使之不至于总是因等待用户响应而无所事事。(2)如果把程序分成若干个线程,这些程序可能更容易编写。(3)某些程序特别适合于并行处理,按线程方式编写这样的程序将会更顺理成章。
6. 获得新线程的两种方法。(1)扩展Thread类。(2)实现Runnable接口。第1种方法只能在类没有扩展其他任何类的情况下使用。
7. 扩展Thread类。
// 扩展Thread类 class Plum extends Thread{ public void run(){/* more code */} } // 启动Plum线程 Plum p = new Plum(); p.start();
8. 实现Runnable接口。
// 实现Runnable接口 class Mango implements Runnable{ public void run(){/* more code */} } // 启动Mango线程 Mango m = new Mango(); Thread t1 = new Thread(m); t1.start();
9. run()方法是线程真正开始执行的地方。在run()方法中,程序员可以按照常规方法,调用其他方法和其他类。start()方法是启动线程。
10. 我们不能让实现了Runnable接口的run()方法中的语句调用Thread方法。Runnable对象中不存在Thread对象。为了在Runnable接口的run()方法中获取线程对象,必须调用Thread的静态方法currentThread()获取当前正在运行的线程。
11. 在创建Thread子类时,我们可以在构造函数中提供一个字符串参数,表示Thread子类对象的名称。
// 在构造方法中提供线程名称 class Grape extends Thread{ Grape(String name){super(name);} public void run(){/* more code */} } // 创建名称为"merlot"的线程 new Grape("merlot").start();
12. 调用getName()方法可以获取线程的名称。
13. 线程的生命周期。当run()方法运行结束或离开run()方法,线程将结束执行。如果run()方法中出现异常,运行时系统将会输入错误信息,并说明线程已经终止。但异常信息不会传播到创建和启动线程的代码中。
14. 设置和改变线程的优先权。如果两个线程均已就绪,优先权高的线程将会先执行。在Java中,一个拥有较高优先权的线程可以强制一个正在运行的线程提前放弃它所占用的处理器。正在运行的线程可以与拥有相同优先权的线程共享处理器。
15. 一旦线程开始执行,其他具有相同优先权的所有线程也许会陷入封锁状态。我们不建议动态地调整线程的优先权,因为这将增大软件维护的难度和成本。我们可以选择频繁地让出对CPU的控制,以便其他线程运行。过度使用CPU的线程应当适当按常规的时间间隔调用yield()方法,确保不会总占用CPU。
16. 在Java中,优先权分配范围从1到10,1表示最低,10表示最高。线程开始运行时具有与其父线程相同的优先级。
17. 调整线程的优先级。
// 调整优先权 t1.setPriority(t1.getPriority() + 1);
18. 线程组就是一组线程。一个线程组还可以包含其他线程组。
19. 线程组的作用是把若干相关的线程合并到一起执行,作为一个整体统一进行控制。
20. 在Java中,可以创建线程组,把线程加到线程组中。
// 获取线程组的引用 private ThreadGroup group; group = Thread.currentThread().getThreadGroup();
21. 新的java.util.concurrent包的设计者建议,不要过多地使用线程组。
22. Java运行时库中曾经有一个经验性的规定,认为一个程序最多可以并发运行26个线程。
23. 程序员也许没有保存对线程的引用,但运行时系统将会保存这一引用。
24. 流程控制到达main()方法的结束位置而GUI程序仍然没有终止的原因:运行时库中还有某些窗口系统线程在运行。