1.定义、实例化并启动线程
(1) 通过扩展Thread和重写public void run()方法创建线程
(2) 通过调用带Runnable变元的Thread构造函数,也可创建Thread对象。Runnable对象称为线程的目标
(3) 只能在Thread对象上调用一次start()方法。如果在Thread对象上多次调用start(),则会抛出RuntimeException异常
(4) 将同一个Runnable对象作为目标创建多个Thread对象是合法的
(5) 当创建Thread对象时,在调用其start()方法之前,它不会变成执行线程。当Thread对象已经存在但还没有启动时,它就处于新状态,但还不是活线程
2.线程状态与转换
(1) 一旦启动了新线程,它将总是进入可运行状态
(2) 线程调度器能够将线程在可运行状态和运行中状态之间来回转换
(3) 对于典型的单处理器机器,尽管可能有多个线程处于可运行状态,但一次只能有一个线程处于可运行状态
(4) 无法保证通过线程的启动顺序来决定它们的运行顺序
(5) 不能保证线程按照任何公平的方法轮流运行。这是线程调度器的责任,而它是由具体的虚拟机实现决定的。如果要保证不管底层JVM如何,都希望线程轮流运行,则可以使用sleep()方法。这会防止一个线程占用过长的运行时间,而其它线程得不到机会[尽管在大多数情况下,yield()也会同样出色,能让线程良好地一起运转]
(6) 调用wait()、sleep()或join(),可以是运行中线程进入阻塞/等待状态
(7) 由于无法获得同步代码块的锁,运行中线程可能进入阻塞/等待状态
(8) 当睡眠或等待结束,或对象的锁变为可用时,线程只能重新进入可运行状态。线程会直接从等待状态进入运行中状态
(9) 不能再次启动死线程
3.睡眠、让步和加入
(1) 睡眠用于延迟执行一段时间,当线程进入睡眠时,不释放任何锁
(2) 可以保证睡眠线程至少睡眠在sleep()方法的变元中指定的时间(除非中断它),但,不能保证刚醒来的线程什么时候会返回到运行中状态
(3) sleep()方法是一个静态方法,它会使当前正在执行的线程的状态睡眠。一个线程不能通知另一个线程睡眠
(4) 利用Thread对象上的setPriority()方法,能为线程提供从1(低)到10(高)的优先级,但优先级是没有保证的,而且并不是所有的JVM都能识别10个不同的优先级,一些优先级可能会被认为是相等的
(5) 若没有明确设置,则线程的优先级将与创建它的线程具有相同的优先级
(6) 若有一个相同优先级的可运行线程,则yield()方法可导致运行中的线程让步。但不能保证这会实际发生,也不能保证在该线程让步后,不会选择一个不同的线程来运行.线程可能让步,然后又理解重新进入运行中状态
(7) 最可保证的是在任何指定的时间,当一个线程正在运行时,其优先级通常不会比处于可运行状态的线程的优先级低。若高优先级的线程进入可运行状态,且低优先级的线程正则运行时,则JVM通常会抢占低优先级的运行中线程,而让高优先级的线程进入运行中状态
(8) 当一个线程调用另一个线程的join()方法时,当前的运行中线程将等待,直到它加入的线程完成时为止。可将join()方法理解成它在说:”喂,线程,我想加在你的后面,当你完成时请通知我,以便我能进入可运行状态”
4.并发访问问题与同步线程
(1) 同步方法可防止多个线程同时访问一个对象的关键方法代码
(2) 可以将synchronized关键字用作方法的修饰符,或者用于同步的代码块
(3) 要同步代码块,必须指定一个变元,它就是希望对其锁进行同步的对象
(4) 尽管只有一个线程能够访问特定实例的同步代码,多个线程仍然可以访问同一个对象的非同步代码
(5) 当线程睡眠时,它的锁对其它线程是不可用的
(6) 使用来自于java.lang.Class表示该类的实例的锁,可以同步静态方法
5.通知等待与通知与对象通信
(1) wait()方法让线程说:”现在我无事可做,请将我放到你的等待池中,当我所关心的事情发生时,请通知我”基本而言,调用wait()是指”请在你的池内等我”,或者”请将我加入到你的等待列表中”
(2) notify()方法用于向在同一个对象的等待池内正在等待的一个并且是唯一一个线程发送信号
(3) notify()不可以指定通知哪个等待线程
(4) notifyAll()方法的工作方式与notify()相同,只不过它是将信号发送给在该对象上等待的所有线程
(5) 必须在同步方法内调用wait()、notify()和notifyAll()。线程在特定的对象上调用wait()或notify()时,该线程当前必须拥有这个对象上的锁
6.死锁的线程
(1) 当代码等待从对象删除锁而迫使线程执行暂停时,死锁又出现了
(2) 当被锁的对象试图访问另一个被锁的对象,而该对象又要访问第一个被锁的对象时,就会发生死锁现象。即:两个线程都在等待对方释放锁,因此,这些锁永远不会释放
(3) 死锁不应当让它发生