第三部分 线程安全(3)——线程同步

本文深入探讨了线程同步的重要性及其实现方式,包括单实例线程的同步锁、多实例线程的同步锁以及线程死锁的问题。通过具体代码示例展示了不同情况下线程同步的正确使用方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当已经有线程在执行这段代码块时,其他的线程必须等待其执行完毕才能进入这段代码块——这就是所谓的线程同步。

一.单实例线程的同步锁

首先看个实例,由于缺少线程同步机制,导致线程执行结果的错误。

实例代码【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

<!--EndFragment-->

造成这一结果的原因在于,当线程ThreadA向列表中添加一个元素之后,线程ThreadB也向其中添加了一个元素,由此造成两个线程均认为列表中的元素个数为2,而事实上,在线程ThreadA完成添加之后列表中的元素个数只有1。下面对代码进行修改,把注释部分去掉。

代码如下:

<!--EndFragment-->

/** * 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(); } }

<!--EndFragment-->

<!--EndFragment-->

<!--EndFragment-->

<!--EndFragment-->

同步锁后的代码:

<!--EndFragment-->

<!--EndFragment-->

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值