当已经有线程在执行这段代码块时,其他的线程必须等待其执行完毕才能进入这段代码块——这就是所谓的线程同步。
一.单实例线程的同步锁
首先看个实例,由于缺少线程同步机制,导致线程执行结果的错误。
实例代码【TestSynchronizationUsingRunnable】
运行结果:
ThreadA 共有元素:2
ThreadB 共有元素:2
造成这一结果的原因在于,当线程ThreadA 向列表中添加一个元素之后,线程ThreadB也向其中添加了一个元素,由此造成两个线程均认为列表中的元素个数为2,而事实上,在线程ThreadA完成添加之后列表中的元素个数只有1。 下面对代码进行修改,把注释部分去掉。
代码如下:
执行结果:
“synchronized(this)”中的this代表锁定的对象实际上是Runnable对象,而一旦锁定了Runnable对象,便实现了线程同步。
二.多实例线程的同步锁
上面说的是单实例,多线程,现在说多实例,多线程。多线程没有基于共同的线程对象,那么如何实现它们之间的同步呢?
首先看一下同步之前的代码【TestSynchronizationUsingThread】
执行结果:
ThreadA 最后一个元素:1
ThreadB 最后一个元素:1
执行结果:
ThreadA 最后一个元素:0
ThreadB 最后一个元素:1
至此,我们可以对同步锁做出一个定义:当线程执行到synchronized的时候,检查传入的实参对象,并得到该对象的锁旗标。如果得不到,那么线程就会被加入到一个与该对象的锁旗标相关联的等待线程池中,一直等到对象的锁旗标被归还,池中的等待线程就会得到该锁旗表,如何继续执行下去。当线程执行完成同步代码块,就会自动释放,它占有的同步对象的锁旗标。
三.线程死锁
在启用同步锁机制后,有两种对象是需要避免的。一是无限等待,二是循环等待。都会导致线程死锁。
1.无限等待:线程B等待线程A完成同步锁内的代码块后释放同步锁,然而线程A却陷入了死循环。导致无法释放同步锁,这将进一步导致线程B陷入无限等待。例如:
synchronized(this)
{
while(true)
{....}
}
2. 循环等待:线程A锁住了对象1,等待对象2的释放,线程B锁住了对象2,等待对象1的释放,从而造成了死锁。
下面代码就是对死锁进一步的解释。
同步锁后的代码: