第三部分 线程安全(3)——线程同步
2011-01-19 10:32
211 查看
当已经有线程在执行这段代码块时,其他的线程必须等待其执行完毕才能进入这段代码块——这就是所谓的线程同步。
实例代码【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的释放,从而造成了死锁。
下面代码就是对死锁进一步的解释。
同步锁后的代码:
一.单实例线程的同步锁
首先看个实例,由于缺少线程同步机制,导致线程执行结果的错误。实例代码【TestSynchronizationUsingRunnable】
/** * TestSynchronizationUsingRunnable.java * 版权所有(C) 2011 cuiran2001@163.com * 创建:崔冉 2011-1-13 下午04:28:31 */ package com.cayden.thread813; import java.util.ArrayList; import java.util.List; /** * @author 崔冉 * @version 1.0.0 * @desc */ public class TestSynchronizationUsingRunnable { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Runnable threadBody=new ThreadBody(new ArrayList()); Thread threada=new Thread(threadBody,"ThreadA"); Thread threadb=new Thread(threadBody,"ThreadB"); threada.start(); threadb.start(); } } class ThreadBody implements Runnable { List intList=null; public ThreadBody(List list){ intList=list; } @Override public void run() { // TODO Auto-generated method stub // synchronized(this){ intList.add(new Integer(123)); try{ Thread.sleep(500); }catch (InterruptedException e) { // TODO: handle exception } System.out.println(Thread.currentThread().getName()+"/t共有元素:"+intList.size()); // } } }
运行结果:
ThreadA 共有元素:2
ThreadB 共有元素:2
造成这一结果的原因在于,当线程ThreadA 向列表中添加一个元素之后,线程ThreadB也向其中添加了一个元素,由此造成两个线程均认为列表中的元素个数为2,而事实上,在线程ThreadA完成添加之后列表中的元素个数只有1。 下面对代码进行修改,把注释部分去掉。
代码如下:
/** * TestSynchronizationUsingRunnable.java * 版权所有(C) 2011 cuiran2001@163.com * 创建:崔冉 2011-1-13 下午04:28:31 */ package com.cayden.thread813; import java.util.ArrayList; import java.util.List; /** * @author 崔冉 * @version 1.0.0 * @desc */ public class TestSynchronizationUsingRunnable { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Runnable threadBody=new ThreadBody(new ArrayList()); Thread threada=new Thread(threadBody,"ThreadA"); Thread threadb=new Thread(threadBody,"ThreadB"); threada.start(); threadb.start(); } } class ThreadBody implements Runnable { List intList=null; public ThreadBody(List list){ intList=list; } @Override public void run() { // TODO Auto-generated method stub synchronized(this){ intList.add(new Integer(123)); try{ Thread.sleep(500); }catch (InterruptedException e) { // TODO: handle exception } System.out.println(Thread.currentThread().getName()+"/t共有元素:"+intList.size()); } } }
执行结果:
ThreadA 共有元素:1 ThreadB 共有元素:2
“synchronized(this)”中的this代表锁定的对象实际上是Runnable对象,而一旦锁定了Runnable对象,便实现了线程同步。
二.多实例线程的同步锁
上面说的是单实例,多线程,现在说多实例,多线程。多线程没有基于共同的线程对象,那么如何实现它们之间的同步呢?首先看一下同步之前的代码【TestSynchronizationUsingThread】
/** * TestSynchronizationUsingThread.java * 版权所有(C) 2011 cuiran2001@163.com * 创建:崔冉 2011-1-13 下午04:51:04 */ package com.cayden.thread813; import java.util.ArrayList; import java.util.List; /** * @author 崔冉 * @version 1.0.0 * @desc */ public class TestSynchronizationUsingThread { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub final List intList=new ArrayList(); Thread threada=new Thread("ThreadA") { public void run(){ // synchronized(intList){//同步 intList.add(new Integer(0)); try{ Thread.sleep(500); }catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"/t最后一个元素:"+intList.get(intList.size()-1)); // } } }; Thread threadb=new Thread("ThreadB") { public void run(){ // synchronized(intList){//同步 intList.add(new Integer(1)); try{ Thread.sleep(500); }catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"/t最后一个元素:"+intList.get(intList.size()-1)); // } } }; threada.start(); threadb.start(); } }
执行结果:
ThreadA 最后一个元素:1
ThreadB 最后一个元素:1
/** * TestSynchronizationUsingThread.java * 版权所有(C) 2011 cuiran2001@163.com * 创建:崔冉 2011-1-13 下午04:51:04 */ package com.cayden.thread813; import java.util.ArrayList; import java.util.List; /** * @author 崔冉 * @version 1.0.0 * @desc */ public class TestSynchronizationUsingThread { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub final List intList=new ArrayList(); Thread threada=new Thread("ThreadA") { public void run(){ synchronized(intList){//同步 intList.add(new Integer(0)); try{ Thread.sleep(500); }catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"/t最后一个元素:"+intList.get(intList.size()-1)); } } }; Thread threadb=new Thread("ThreadB") { public void run(){ synchronized(intList){//同步 intList.add(new Integer(1)); try{ Thread.sleep(500); }catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"/t最后一个元素:"+intList.get(intList.size()-1)); } } }; threada.start(); threadb.start(); } }
执行结果:
ThreadA 最后一个元素:0
ThreadB 最后一个元素:1
至此,我们可以对同步锁做出一个定义:当线程执行到synchronized的时候,检查传入的实参对象,并得到该对象的锁旗标。如果得不到,那么线程就会被加入到一个与该对象的锁旗标相关联的等待线程池中,一直等到对象的锁旗标被归还,池中的等待线程就会得到该锁旗表,如何继续执行下去。当线程执行完成同步代码块,就会自动释放,它占有的同步对象的锁旗标。
三.线程死锁
在启用同步锁机制后,有两种对象是需要避免的。一是无限等待,二是循环等待。都会导致线程死锁。1.无限等待:线程B等待线程A完成同步锁内的代码块后释放同步锁,然而线程A却陷入了死循环。导致无法释放同步锁,这将进一步导致线程B陷入无限等待。例如:
synchronized(this)
{
while(true)
{....}
}
2. 循环等待:线程A锁住了对象1,等待对象2的释放,线程B锁住了对象2,等待对象1的释放,从而造成了死锁。
下面代码就是对死锁进一步的解释。
/** * TestDeadLock.java * 版权所有(C) 2011 cuiran2001@163.com * 创建:崔冉 2011-1-13 下午05:03:56 */ package com.cayden.thread813; /** * @author 崔冉 * @version 1.0.0 * @desc */ public class TestDeadLock { static final ClassA classA=new ClassA(); static final ClassB classB=new ClassB(); /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Thread threada=new Thread("ThreadA") { public void run(){ classA.method1(); } }; Thread threadb=new Thread("ThreadB") { public void run(){ classB.method2(); } }; threada.start(); threadb.start(); } } class ClassA{ public static synchronized void method1 () { ClassB.method2(); } } class ClassB{ public static synchronized void method2 () { ClassA.method1(); } }
同步锁后的代码:
相关文章推荐
- 第三部分 线程安全(3)——线程同步
- 翻译:Visual C# 4.0的新特性-第三部分-Dynamic ExpendoObject
- 了解 Windows Vista 内核:第三部分
- (3) 深入理解SELinux SEAndroid(第三部分 - over)
- 第17章 高级数据表示 17.7 二叉搜索树 (第三部分 试用树)
- 一步一步学习sharepoint2010 workflow 系列第三部分:自定义SharePoint代码工作流 第10章 工作流和任务处理(Workflows and task processes)
- Web探索之旅 | 第三部分第二课:IP地址和域名
- Linux探索之旅 | 第二部分第三课:文件和目录,组织不会亏待你
- Linux探索之旅 | 第四部分第三课:文件传输,潇洒同步
- 在 Eclipse 3.1 中体验 J2SE 5.0 的新特性: 第三部分 :范型
- Prism4文档翻译(第一章 第三部分)
- 《java.util.concurrent 包源码阅读》13 线程池系列之ThreadPoolExecutor 第三部分
- 分享:Go net/http 包 第三部分 翻译完毕
- 第三部分:Android 应用程序接口指南---第一节:应用程序组件---第二章2-2.AIDL
- 第三部分:Android 应用程序接口指南---第一节:应用程序组件---第五章 Android中的进程与线程
- java并发编程:线程安全-线程同步-synchronized和lock
- C#语言 第五部分 线程(二) 线程同步(1)
- MIT自然语言处理第一讲:简介和概述(第三部分)
- 转:如何学习SQL(第三部分:SQL数据类型与三值逻辑)
- cocos2d-iphone之魔塔20层第三部分