Vector 、 Hashtable都是线程安全的。
竞争资源(共享资源) - 如果有多条线程需要并发访问、并修改某个对象,
该对象就是“竞争资源”。
为了避免多个线程“自由竞争”修改共享资源所导致的不安全问题。
于是就考虑“加锁”。
第一种方式:用同步代码块。
—— 需要显式指定同步监视器。
第二种方式:同步方法。
—— 相当于使用方法调用者作为同步监视器。
如果方法是实例方法,相当于this作为同步监视器。
如果方法是类方法,相当于以类作为同步监视器。
它们的实现机制是完全相同的:当线程要进入被“同步监视器”监视的代码之前
线程必须先获得对“同步监视器”锁定。
这样就保证在任意一个时刻,只有一条线程能进入被“同步监视器”监视的代码。
从语法角度来看,任意对象都可作为同步监视器(Monitor)。
——从程序逻辑来看,选择“竞争资源”作为同步监视器。
线程同步的关键:
任意的线程,进入【同步监视器】监视的代码之前,必须先对【同步监视器】加锁。
什么时候会释放对【同步监视器】的加锁
A。 同步代码块或同步方法执行完成。
B。 在代码块遇到break、return跳出了该代码块。
C。 执行同步代码块或同步方法时遇到未捕获的异常。
D。 调用了同步监视器的wait()方法。
下面这些情况不会释放。
A。 sleep()、yield()都不会释放。
B。 suspend()也不会释放。
线程通信
1. 如果不加控制,多个线程“自由”地并发执行。
2. 可以通过同步,来解决多个线程并发访问竞争资源的问题。
线程安全,必然带来性能的降低。(Vector,Hashtable)
Java倡议为很多类提供两个版本:线程安全的版本,适合多线程访问。 StringBuffer
线程不安全的版本,适合单线程环境 StringBuilder
3. 如果希望线程之间能更有序地执行。
(生产者 - 消费者)问题。
Object 的如下方法:
wait() - 控制线程暂停,释放对【同步监视器】的加锁
它会一直等待,直到收到“唤醒”通知。
notify() - 发送唤醒通知。
notifyAll() - 发送唤醒通知。
——只有同步监视器【不是用线程调用】才能调用这3个方法!