马士兵-多线程学习第04课 线程的同步

 本人地址:http://blog.csdn.net/hblfyla/article/details/53001587

1.思考为什么会有线程的同步?线程不同步会带来哪些问题?

       我们首先要来了解一个例子,假设我有一张银行卡和存折共享里面的钱,假设有3000块钱,有一天我去银行拿着存折去取钱,到了柜台我取2000块钱,银行开始计算,里面有3000,够2000,开始进行取钱操作,但是还没有计算3000-2000的结果的时候,我老婆拿这银行卡去ATM里面取钱,也要取2000,一查卡里面有3000块钱,开始取钱,3000-2000=1000取钱完毕,老婆完毕,我这边现在也开始计算3000-2000=1000,取钱完毕,那么我们卡里面还有1000块钱,我和老婆一共取了4000块钱,者就是由于共享数据不同问题产生的效果。银行肯定不会让那么干的,现在有一个解决的办法就是不管是谁取钱的时候,对这个共享的变量钱,进行上锁操作,在相同的时间里只能够有一个人进行操作,这样子就不会出钱这种情况了

       下面我们用画图的方式来说明下上面的例子。

马士兵-多线程学习第04课 线程的同步_第1张图片

下面我们来用代码来模拟这个程序:

public class TestSyc01 implements Runnable {
	private MyThread m = new MyThread();
	@Override
	public void run() {
		m.add();
	}
	public static void main(String[] args) {
		TestSyc01 ts = new TestSyc01();
		Thread t1 = new Thread(ts, "A");
		Thread t2 = new Thread(ts, "B");
		t1.start();
		t2.start();
	}
}
class MyThread {
	private static int num = 0;
	public void add() {
		num++;
		try {
			Thread.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName() + "是第" + num
				+ "次调用");
	}
}

运行效果:

A是第2次调用
B是第2次调用

运行分析:

马士兵-多线程学习第04课 线程的同步_第2张图片

2.针对上面的例子,我们来看一下解决办法,加锁使用synchronized
代码:
package org.yla.msb.day04;
public class TestSyc01 implements Runnable {
	private MyThread m = new MyThread();
	@Override
	public void run() {
		m.add();
	}
	public static void main(String[] args) {
		TestSyc01 ts = new TestSyc01();
		Thread t1 = new Thread(ts, "A");
		Thread t2 = new Thread(ts, "B");
		t1.start();
		t2.start();
	}
}
class MyThread {
	private static int num = 0;
	public synchronized void add() {   //在执行add方法时候锁定当前对象
//		synchronized(this){  //锁定当前对象 new的对象 此代码块开始
			num++;
			try {
				Thread.sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName() + "是第" + num+ "次调用");
//		}
		
	}
}

运行效果:

A是第1次调用
B是第2次调用

注意使用同步的两种方法一个是同步代码块一个是同步方法,两者的区别已经在上面的代码中注释

 
3.多线程使用同步的时候,可能会带来死锁
        下面我们来看一下死锁产生的原因
        假设两个线程,A线程在锁住一个对象a后,执行程序,主要再的得到b对象的锁,就可以执行完毕程序
                                   B线程先锁住b对象的锁,只要在得到a对象的锁,程序就可以执行完毕,图如下所示:
马士兵-多线程学习第04课 线程的同步_第3张图片

       简言之,就是假就是必须对两个对象进行锁,已经锁住一个对象后,等待锁下一个对象的时候,发现这个对象被其他人锁定,只能等待,另外一个正好相反
代码实现:
package org.yla.msb.day05;
/**
 * 测试多线程的锁死产生
 * 
 * @author yangluan 2016年10月30日下午8:12:54
 */
public class TestThreadDeadLock implements Runnable {
	private int flag = 1; // 标记为用来区分所对象的
	private static Object o1 = new Object(); // 对象o1
	private static Object o2 = new Object(); // 对象02
	
	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName()+": flag= "+flag);
		if (flag == 1) {
			synchronized (o1) {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("1");
				synchronized (o2) {
					System.out.println("2");
				}
			}
		}
		
		if (flag == 0) {
			synchronized (o2) {
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("2");
				synchronized (o1) {
					System.out.println("1");
				}
			}
		}
	}
	public static void main(String[] args) {
		//生命两个对象
		TestThreadDeadLock td1 = new TestThreadDeadLock();
		TestThreadDeadLock td2 = new TestThreadDeadLock();
		
		//分别加入把对象加入到两个不容的线程中 
		Thread t1 = new Thread(td1);
		Thread t2 = new Thread(td2);
		
		//设置程序代码的逻辑
		td1.flag=1;	
		td2.flag=0;
		
		//线程启动 
		t1.start();
		t2.start();
		
		
		
	}
}

运行结果:

马士兵-多线程学习第04课 线程的同步_第4张图片


例子2:

package org.yla.msb.day05;
/**
 * 测试线程死锁的产生
 * 张三对李四 你把书给我,我给你笔
 * 李四对张三 “你把笔给我,我给你书
 * 结果:都不先给 ,都没得到就是死锁
 * @author yangluan
 * 2016年10月30日下午8:43:30
 */
class Zhangsan{
	public void say(){
		System.out.println("张三对李四说:“你把书给我,我给你笔”");
	}
	
	public void get(){
		System.out.println("张三得到书了");
	}
}
class List{
	public void say(){
		System.out.println("李四对张三说:“你把笔给我,我给你书”");
	}
	
	public void get(){
		System.out.println("李四得到笔了");
	}
}
public class TestThreadDeadLocklxh implements Runnable{
	private static Zhangsan zs = new Zhangsan();
	private static List ls = new List();
	
	private boolean flag= false;
	
	@Override
	public void run() {
		if(flag){
			synchronized(zs){
				zs.say();
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				synchronized(ls){
					zs.get();
				}
				
			}
		}else{
			synchronized(ls){
				ls.say();
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				synchronized(zs){
					ls.get();
				}
			}
		}
	}
	
	public static void main(String[] args) {
		TestThreadDeadLocklxh tt1 = new TestThreadDeadLocklxh();
		TestThreadDeadLocklxh tt2 = new TestThreadDeadLocklxh();
		tt1.flag=true;
		tt2.flag=false;
		Thread t1 = new Thread(tt1);
		Thread t2 = new Thread(tt2);
		t1.start();
		t2.start();
	}
}

运行:

 本人地址:http://blog.csdn.net/hblfyla/article/details/53001587

你可能感兴趣的:(多线程)