多线程程序就好像一个海王,所有线程都在它的鱼塘且互相不知道别的存在。
多进程与多线程有着本质的区别,每个进程都拥有自己的一套变量,而线程则共享数据。线程最简单的3个状态分别是:New(新建),Runnable(可执行),Blocked(阻塞)。当用new创建一个线程时,这个线程还没有开始运行,它的状态便是New;一旦调用start方法,线程就会处于Runnable状态,只不过它可能在运行也可能并没有运行,它不一定始终保持运行,可能会小睡一会儿以让其他线程运行。这依赖于线程调度器,它会决定哪个线程运行哪个线程被踢出,而我们不能很好地保证。线程调度器也可能因为某些原因让某些线程暂时处于不可运行的状态,即为阻塞。
当多线程需要共享同一对象而且都有可以修改对象状态的方法时,常会引发竞态条件(race condition),会引发数据的损毁。例如一个典型的问题——丢失更新。举一个简单的例子,线程A和线程B都可以对某一个整型数据进行读写。A有三个步骤分别是读取,将读出来的值+1,写入;B有三个步骤分别是读取,将读出来的值+2,写入;当线程A执行时,读取的值为0,计算应该写入的值为1,这时,线程调度器将A踢出了,B开始执行。由于A还没有写入,因此B读取的值也为0,计算应该写入的值为2,于是这个数据的值变为了2,这时候,线程调度器又随机安排A执行,而A并不知道刚刚B做了什么,它就像睡着了失去了意识,睡醒之后继续工作,将1写入数据,于是这个数据的值变为了1,此时线程B刚刚对数据的更新完全消失了,这便是“丢失更新”。
这种问题可以使用同步机制来解决,给对象上锁,确保使任何时刻都只有一个线程进入对象,并且在该线程执行结束前不会将钥匙交给其他线程。