传统线程互斥技术初步-synchronized常用的几个锁对象
2016-07-27 13:17
543 查看
—————-本系列文章作为学习张孝祥老师系列视频的笔记。—————
该程序的结构是一个定义了一个打印方法的外部类和一个启动2个线程的主类。
然后2个线程进入没有同步的打印语句块,从而产生了下列运行结果:
出现这样结果的原因是某一线程打印时被另一线程打断然后出现了打印混乱的情况。
程序如下:
结果正常打印:
从上面程序可以看出,锁是字符串对象lock,并且lock只有一个。2个线程用的都是一个lock;
运行结果正常,这里不贴出来了。
需要说明的是,如果在方法前面加synchronized为方法加锁,那么线程持有的锁对象是调用该方法的那个对象,比如上述程序的锁就是out这个对象。
我们知道,静态方法执行时不需要创建一个实例对象,那么我们此时要将该类的一个属性与锁联系起来,显然这个对象就是该类加载时产生的class对象。
另外,只要2个线程执行逻辑语句的时候,它们需要的锁是同一个锁,那么就能产生同步效果。比如线程A需要锁x来执行方法m,线程B执行方法n的时候也需要锁m,此时虽然它们执行不同的方法,但是需要的锁是一样的。因此也能产生同步效果。
下面是一个Demo:
该程序的运行结果也是正常打印的。
1.非同步情况下线程的运行
首先看一个程序:public class TraditionalSynchronizedLock { public static void main(String[] args) { OutDemo out = new OutDemo(); new Thread(new Runnable() { @Override public void run() { while (true) { try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } out.output("i love vayne"); } } }).start(); new Thread(new Runnable() { @Override public void run() { while (true) { try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } out.output("my csdn blog"); } } }).start(); } } class OutDemo { public void output(String string) { int len = string.length(); for (int i = 0; i < len; i++) { System.out.print(string.charAt(i)); } System.out.println(); } }
该程序的结构是一个定义了一个打印方法的外部类和一个启动2个线程的主类。
然后2个线程进入没有同步的打印语句块,从而产生了下列运行结果:
imy c slove vaynden bl og imy csdn blog love vayne my csdn blog i love vayne my csdn blog i love vayne my csdn blog i love vayne my csdn blog i love vayne my csdn blog i love vayne my csdn blog i love vayne
出现这样结果的原因是某一线程打印时被另一线程打断然后出现了打印混乱的情况。
2.使用一个额外的对象作为 锁
现在我们给打印块加锁,注意这个锁必须是同一把锁,即用的锁对象是同一个:程序如下:
public class TraditionalSynchronizedLock { public static void main(String[] args) { OutDemo out = new OutDemo(); new Thread(new Runnable() { @Override public void run() { while (true) { try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } out.output("i love vayne"); } } }).start(); new Thread(new Runnable() { @Override public void run() { while (true) { try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } out.output("my csdn blog"); } } }).start(); } } class OutDemo { String lock = ""; public void output(String string) { int len = string.length(); synchronized (lock) { for (int i = 0; i < len; i++) { System.out.print(string.charAt(i)); } System.out.println(); } } }
结果正常打印:
i love vayne my csdn blog i love vayne my csdn blog i love vayne my csdn blog i love vayne my csdn blog i love vayne my csdn blog i love vayne my csdn blog
从上面程序可以看出,锁是字符串对象lock,并且lock只有一个。2个线程用的都是一个lock;
3.使用对象锁
下面使用调用打印方法的OutDemo对象作为锁:public class TraditionalSynchronizedLock { public static void main(String[] args) { OutDemo out = new OutDemo(); new Thread(new Runnable() { @Override public void run() { while (true) { try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } out.output("i love vayne"); } } }).start(); new Thread(new Runnable() { @Override public void run() { while (true) { try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } out.output("my csdn blog"); } } }).start(); } } class OutDemo { public synchronized void output(String string) { int len = string.length(); for (int i = 0; i < len; i++) { System.out.print(string.charAt(i)); } System.out.println(); } }
运行结果正常,这里不贴出来了。
需要说明的是,如果在方法前面加synchronized为方法加锁,那么线程持有的锁对象是调用该方法的那个对象,比如上述程序的锁就是out这个对象。
4.使用类的字节码作为锁
现在我们来考虑这样一种情况:OutDemo类有一个打印方法是静态方法,而且该方法前面加了synchronized进行同步,那么此时它用的是哪个对象当锁呢?我们知道,静态方法执行时不需要创建一个实例对象,那么我们此时要将该类的一个属性与锁联系起来,显然这个对象就是该类加载时产生的class对象。
另外,只要2个线程执行逻辑语句的时候,它们需要的锁是同一个锁,那么就能产生同步效果。比如线程A需要锁x来执行方法m,线程B执行方法n的时候也需要锁m,此时虽然它们执行不同的方法,但是需要的锁是一样的。因此也能产生同步效果。
下面是一个Demo:
public class TraditionalSynchronizedLock { public static void main(String[] args) { OutDemo out = new OutDemo(); new Thread(new Runnable() { @Override public void run() { while (true) { try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } OutDemo.output("i love vayne"); } } }).start(); new Thread(new Runnable() { @Override public void run() { while (true) { try { Thread.sleep(10); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } out.output2("my csdn blog"); } } }).start(); } } class OutDemo { public static synchronized void output(String string) { int len = string.length(); for (int i = 0; i < len; i++) { System.out.print(string.charAt(i)); } System.out.println(); } public void output2(String string) { int len = string.length(); synchronized (OutDemo.class) { for (int i = 0; i < len; i++) { System.out.print(string.charAt(i)); } System.out.println(); } } }
该程序的运行结果也是正常打印的。
相关文章推荐
- C#线程间不能调用剪切板的解决方法
- C#线程同步的三类情景分析
- C#获取进程或线程相关信息的方法
- 简单对比C#程序中的单线程与多线程设计
- C#停止线程的方法
- C#子线程更新UI控件的方法实例总结
- C#线程队列用法实例分析
- C++使用CriticalSection实现线程同步实例
- 基于C++实现的线程休眠代码
- VB读取线程、句柄及写入内存的API代码实例
- C#网络编程基础之进程和线程详解
- C#通过Semaphore类控制线程队列的方法
- C#多线程处理多个队列数据的方法
- C#实现线程安全的简易日志记录方法
- C#中线程同步对象的方法分析
- ASP.NET线程相关配置
- C#创建线程带参数的方法
- 浅析linux环境下一个进程最多能有多少个线程
- 再谈JavaScript线程
- C#实现终止正在执行的线程