多线程3

1 多线程的三种加锁方式

  /*
 * A:同步代码块的锁对象是谁呢?
 *         任意对象。
 *
 * B:同步方法的格式及锁对象问题?

	 private synchronized void sellTicket() {
			if (tickets > 0) {
			try {
					Thread.sleep(100);
			} catch (InterruptedException e) {
					e.printStackTrace();
			}
			System.out.println(Thread.currentThread().getName()
						+ "正在出售第" + (tickets--) + "张票 ");
			}
	}
	
while (true) {
			if(x%2==0){
				synchronized (this) {
					if (tickets > 0) {
						try {
							Thread.sleep(100);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						System.out.println(Thread.currentThread().getName()
								+ "正在出售第" + (tickets--) + "张票 ");
					}
				}
			}else {
					System.out.println(Thread.currentThread().getName()
//								+ "正在出售第" + (tickets--) + "张票 ");

				
				sellTicket();
				
			}
			x++;
		}
	}


 *         把同步关键字加在方法上。
 *
 *         同步方法是谁呢?
 *             this
 *
 * C:静态方法及锁对象问题?
 *         静态方法的锁对象是谁呢?
 *             类的字节码文件对象。(反射会讲)

private static synchronized void sellTicket() {
		if (tickets > 0) {
		try {
				Thread.sleep(100);
		} catch (InterruptedException e) {
				e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()
					+ "正在出售第" + (tickets--) + "张票 ");
		}
}
}
	@Override
	public void run() {
		while (true) {
			if(x%2==0){
				synchronized (SellTicket.class) {
					if (tickets > 0) {
						try {
							Thread.sleep(100);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
						System.out.println(Thread.currentThread().getName()
								+ "正在出售第" + (tickets--) + "张票 ");
					}
				}
			}else {
                                
				sellTicket();
				
			}
			x++;
		}
	}

  2   死锁的条件

  举一个例子,一个老外和一个中国人去吃饭,给老外的餐具是一只筷子和一把刀,给中国人的餐具是一只筷子和一把叉子,但是两个人都在等待对方吃完,在吃自己的食物,

   其实就是 两个或两个以上的线程在争夺资源的过程中,发生的一种相互等待的现象。

   死锁的代码举例

public class DieLock extends Thread {

	private boolean flag;

	public DieLock(boolean flag) {
		this.flag = flag;
	}

	@Override
	public void run() {
		if (flag) {
			synchronized (MyLock.objA) {
				System.out.println("if objA");
				synchronized (MyLock.objB) {
					System.out.println("if objB");
				}
			}
		} else {
			synchronized (MyLock.objB) {
				System.out.println("else objB");
				synchronized (MyLock.objA) {
					System.out.println("else objA");
				}
			}
		}
	}
}
public class DieLockDemo {
	public static void main(String[] args) {
		DieLock dl1 = new DieLock(true);
		DieLock dl2 = new DieLock(false);

		dl1.start();
		dl2.start();
	}
}

   

public class MyLock {
	// 创建两把锁对象
	public static final Object objA = new Object();
	public static final Object objB = new Object();
}

 


 
 通过控制台我们可以知道,此时编辑器还是运行的,但是发生了死锁,也就是刚运行完了红色的代码,就被另一个线程dl2给抢走了,然后dl2往下运行 ,运行完粉色的代码,发现此时被 另一个给锁上了,返回dl1,但是此时dl1下面的代码也被锁上了,也就是相互等待了。

  

  3 生产者。消费者的问题概述

  那早餐的包子来说,首先是要求老板有包子,顾客才能买,(也就是不能顾客在没有包子的情况下,先买了包子,还有就是顾客在包子买完之后,老板才会继续生产包子)

   

public class SetThread implements Runnable {

	private Student s;
	private int x = 0;

	public SetThread(Student s) {
		this.s = s;
	}

	@Override
	public void run() {
		while (true) {
			if (x % 2 == 0) {
				s.set("林青霞", 27);
			} else {
				s.set("刘意", 30);
			}
			x++;
		}
	}
}

  

public class Student {
	private String name;
	private int age;
	private boolean flag; // 默认情况是没有数据,如果是true,说明有数据

	public synchronized void set(String name, int age) {
		// 如果有数据,就等待
		if (this.flag) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

		// 设置数据
		this.name = name;
		this.age = age;

		// 修改标记
		this.flag = true;
		this.notify();
	}

	public synchronized void get() {
		// 如果没有数据,就等待
		if (!this.flag) {
			try {
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

		// 获取数据
		System.out.println(this.name + "---" + this.age);

		// 修改标记
		this.flag = false;
		this.notify();
	}
}
/*
 * 分析:
 * 		资源类:Student	
 * 		设置学生数据:SetThread(生产者)
 * 		获取学生数据:GetThread(消费者)
 * 		测试类:StudentDemo
 * 
 * 问题1:按照思路写代码,发现数据每次都是:null---0
 * 原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个
 * 如何实现呢?
 * 		在外界把这个数据创建出来,通过构造方法传递给其他的类。
 * 
 * 问题2:为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题
 * 		A:同一个数据出现多次
 * 		B:姓名和年龄不匹配
 * 原因:
 * 		A:同一个数据出现多次
 * 			CPU的一点点时间片的执行权,就足够你执行很多次。
 * 		B:姓名和年龄不匹配
 * 			线程运行的随机性
 * 线程安全问题:
 * 		A:是否是多线程环境		是
 * 		B:是否有共享数据		是
 * 		C:是否有多条语句操作共享数据	是
 * 解决方案:
 * 		加锁。
 * 		注意:
 * 			A:不同种类的线程都要加锁。
 * 			B:不同种类的线程加的锁必须是同一把。
 * 
 * 问题3:虽然数据安全了,但是呢,一次一大片不好看,我就想依次的一次一个输出。
 * 如何实现呢?
 * 		通过Java提供的等待唤醒机制解决。
 * 
 * 等待唤醒:
 * 		Object类中提供了三个方法:
 * 			wait():等待
 * 			notify():唤醒单个线程
 * 			notifyAll():唤醒所有线程
 * 		为什么这些方法不定义在Thread类中呢?
 * 			这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象。
 * 			所以,这些方法必须定义在Object类中。
 * 
 * 最终版代码中:
 * 		把Student的成员变量给私有的了。
 * 		把设置和获取的操作给封装成了功能,并加了同步。
 * 		设置或者获取的线程里面只需要调用方法即可。
 */
public class StudentDemo {
	public static void main(String[] args) {
		//创建资源
		Student s = new Student();
		
		//设置和获取的类
		SetThread st = new SetThread(s);
		GetThread gt = new GetThread(s);

		//线程类
		Thread t1 = new Thread(st);
		Thread t2 = new Thread(gt);

		//启动线程
		t1.start();
		t2.start();
	}
}
public class GetThread implements Runnable {
	private Student s;

	public GetThread(Student s) {
		this.s = s;
	}

	@Override
	public void run() {
		while (true) {
			s.get();
		}
	}
}

  

   

   

   

猜你喜欢

转载自1193355343.iteye.com/blog/2369968