P501-P528
《Head First Java》20201029读书笔记
线程
如果想要确保其他的线程有机会执行的话,就把线程放进睡眠状态。
当线程醒来的时候,它会进入可执行状态等待被调度器挑出来执行。
确保线程能够有机会执行的最好方式是让它们周期性地去睡一下,只要调用sleep()这个方法,传入以毫秒指定的时间就行。
Thread.sleep(2000);
写的线程或许永远不会被中断,这个异常是API用来支持线程间通信的机制,良好的习惯规则会要求我们把有可能抛出异常的调用做妥善的处理。
使用sleep()让程序更加可预测。
线程会产生并发性的问题
问题:两个或以上的线程存取单一对象的数据。也就是说,两个不同执行空间上的方法都在堆上对同一个对象执行getter或setter。
synchronized关键词代表线程需要一把钥匙来存取被同步化(synchronized)过的线程。
要保护数据,就把作用在数据上的方法给同步化。
使用synchronized这个关键词来修饰方法使它每次只能被单一的线程存取。
每个Java对象都有一个锁,每个锁只有一把钥匙。
通常对象都没上锁,也没有人在乎这件事。
但如果对象有同步化的方法,则线程只能在取得钥匙的情况下进入线程。也就是说,并没有其他线程已经进入的情况下才能进入。
一旦线程进入了方法,我们必须确保在其他线程可以进入该方法之前所有的步骤都会完成。
只要两个线程和两个对象就可以引起死锁。
要点
- Thread.sleep()这个静态方法可以强制线程进入等待状态到过了设定时间为止,例如Thread.sleep(200)会睡上200个毫秒。
- 可以调用sleep()让所有的线程都有机会运行。
- sleep()方法可能会抛出InterruptedException异常,所以要包在try/catch块,或者把它也声明出来。
- 你可以用setName()方法来帮线程命名,通常是用来除错的。
- 如果两个或以上的线程存取堆上相同的对象可能会出现严重的问题。
- 如果两个或以上的线程存取相同的对象可能会引发数据的损毁。
- 要让对象在线程上有足够的安全性,就要判断哪些指令不能被分割执行。
- 使用synchronized这个关键词修饰符可以防止两个线程同时进入同一对象的同一方法。
- 每个对象都有单一的锁,单一的钥匙。这只会在对象带有同步化方法时才有实际的用途。
- 线程尝试要进入同步化过的方法时必须要取得对象的钥匙,如果因为已经被别的线程拿走了,那就得等。
- 对象就算是有多个同步化过的方法,也还是只有一个锁。一旦某个线程进入该对象的同步化方法,其他线程就无法进入该对象上的任何同步化线程。