java之Thread(二)

需求:在电影院买票案例

为了模拟更真实的场景,加入延迟操作(让我们线程睡100毫秒)
  程序的设计是好的,但是结果有一些问题
   1)同一张票被卖了多次
   CPU的执行有一个特点(具有原子性操作:最简单最基本的操作)
   2)出现了0或者负票

  (延迟操作+线程的执行随机性)

通过刚才的这个程序,有安全问题(同票还是负票) 
  如何解决多线程的安全问题?
   校验一个多线程程序是否有安全问题的隐患的前提条件:
  1)当前程序是否是多线程环境
   2)是否有共享数据
   3)是否有多条语句对共享数据进行操作
  看当前案例是否有多线程的安全问题:
   1)是否是多线程环境
   2)是否有共享数据
   3)是否有多条语句对共享数据进行操作  是 
  现在就需要解决安全问题:
   1)多线程环境 不能解决
   2)对共享数据进行优化 不能解决
   3)解决将多条语句对共享数据这一环进行解决 
   解决方案:就是将多条语句对共享数据操作的代码,用一个代码包起来---->代码--->同步代码块
   格式:
   synchronized(锁对象){
   针对多条语句对共享数据操作代码;
  }

  锁对象:肯定一个对象,随便创建一个对象(匿名对象) 
   给刚才的这个程序加入了同步代码块,但是锁对象使用的匿名对象(每一个线程进来都有自己的锁),还是没有解决!
   锁对象:每一个线程最总使用的锁对象,只能是同一把锁

举例:

private int ticket=100;
private Object obj =new Object();
@Override
	public void run() {
		while (true) {
//			synchronized(new Object()) {
//				if(ticket>0) {
//					try {
//						Thread.sleep(100);
//					} catch (InterruptedException e) {
//						// TODO Auto-generated catch block
//						e.printStackTrace();
//					}
//					System.out.println(Thread.currentThread().getName()+"正在销售第"+ticket--+"张票");
//				}
//			}
			synchronized(obj) {
				if(ticket>0) {
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()+"正在销售第"+ticket--+"张票");
				}
			}
			}
			}
}

Lock锁和sychronized功能相似

举例:

public class SellTicket implements Runnable {
	// 定义100张票
	private int ticket = 100;
	// 创建锁对象
	private Lock l = new ReentrantLock();

	public void run() {
		while (true) {
			try {
				l.lock();
				if (ticket > 0) {
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName() + "正在销售第" + ticket-- + "张票");
				}
			} finally {
				if (l != null) {
					l.unlock();
				}
			}
		}
	}
}	
Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。此实现允许更灵活的结构
  可以使用Lock锁进行具体的锁定操作类 提供了具体的实现类:ReentrantLock

  加锁并且去释放锁

举例:

public class SellTicket implements Runnable {
	// 定义100张票
	private int ticket = 100;
	// 创建锁对象
	private Lock l = new ReentrantLock();

	public void run() {
		while (true) {
			try {
				l.lock();
				if (ticket > 0) {
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName() + "正在销售第" + ticket-- + "张票");
				}
			} finally {
				if (l != null) {

					l.unlock();
				}
			}
		}
	}
}

注释:最后要释放锁,调用时必须要用锁接口的多态。

 死锁:两个或两个以上的线程,在执行的过程中出现互相等待的情况

解决死锁的办法生产消费设计模式:运用同步方法,等待唤醒机制,来进行解决。

猜你喜欢

转载自blog.csdn.net/wt5264/article/details/80614256