synchronized的实现案例

要求:电影院三个窗口同是卖100张票

1.  按照正常线程问题的结果

package 出票;
//会出现重复100票数,0也会出现
//原因:在线程抢占执行权的时候,可能会出现1号抢到后执行,但是在tickets--还有没有执行
//结束后又再次输出100,出现的混乱
//出现0也是因为--在执行后被线程抢占出现错误数据
public class sell extends Thread{
	
	//private 修饰私有的,不被外界所改变值
	//因为三个窗口一起卖票,所以用static修饰
	//表明是共有的
    private static int tickets=100;
    public void run() {
    	while(true) {
    		if(tickets>0) {
    			System.out.println(getName()+"正在出售"+(tickets--)+"张票");
    		}
    	}
    }
}
package 出票;

public class demo {
   public static void main(String[] args) {
	sell s1=new sell();
	sell s2=new sell();
	sell s3=new sell();
	//无参构造起窗口名字
	s1.setName("1号");
	s2.setName("2号");
	s3.setName("3号");
	//开始运行
	s1.start();
	s2.start();
	s3.start();
}
}

2.   第一次改进

改进后依然是会有重复代码出现, 因为虽然加锁,但是锁对象是匿名出现的,所以没有体现一次进入一个程序的效果

package 出票__改进;

public class sellgai implements Runnable{
	
	//成员变量
		private static int tickets=100;
		@Override
		public void run() {
			while(true) {
				/**出现了0和负数
				         解决方案:就是将多条语句对共享数据操作的代码,用一个代码包起来---->代码--->同步代码块
	 	                               格式:
	 			   synchronized(锁对象){
	 					针对多条语句对共享数据操作代码	}
				 */
				//给代码加入锁,这样每一个线程进来后其他线程就不会进来
				//但是测试后依然有错误数据,原因是匿名自定义了锁对象
				//锁对象就相当于一把钥匙
				//这样无法起到一个线程进来后其他线程进不来的效果
				//因为每个线程都会匿名一个对象,所以同步代码块就没有意义
				synchronized (new Object()) {
				  if(tickets>0) {
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()+"正在出售"+(tickets--)+"张票");
				}else {
					System.exit(0);
				}
			  }
			}
		}
}

3.第二次改进

最终改进成功,不再出现重复数据和错误数据

package 出票__改进2;

public class sellgai2 implements Runnable{
	//成员变量
			private static int tickets=100;
			//在成员变量建立私有的锁对象
			//相当于只有一把钥匙,每个进程要进去都要先获得锁对象
			//有锁对象的可以执行,没有的等待前一个执行结束后重新抢钥匙再执行
			//这样就实现了一次进去一个进程
			private Object obj=new Object();
			@Override
			public void run() {
				while(true) {
					synchronized (obj) {
					  if(tickets>0) {
						try {
							Thread.sleep(100);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						System.out.println(Thread.currentThread().getName()+"正在出售"+(tickets--)+"张票");
					}else {
						System.exit(0);
					}
				  }
				}
			}

}

4.lock锁

package lock锁;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class selllock implements Runnable {

		private static int tickets=100;
		private Lock lock=new ReentrantLock();
		@Override
		public void run() {
			while(true) {
				try {
					lock.lock();
				  if(tickets>0) {
					try {
						Thread.sleep(100);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println(Thread.currentThread().getName()+"正在出售"+(tickets--)+"张票");
				}else {
					System.exit(0);
				}
				 //要在进程结束后释放lock锁,不然会出现如果一个线程抢到
				  //那么其他线程就不会在执行
				  //finally相当于把钥匙还回去,线程再重新抢
				} finally {
					if(lock!=null) {
						lock.unlock();
					}
				} 
			  }
			}
		}
	



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值