A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

为了模拟真实环境,代码加入延时
  1. package com.kxg_09;

  2. public class SellTicekt implements Runnable {
  3.         private int ticket = 100;

  4.         @Override
  5.         public void run() {
  6.                 while (true) {
  7.                         if (ticket > 0) {
  8.                                 try {
  9.                                         Thread.sleep(100);
  10.                                 } catch (InterruptedException e) {
  11.                                         e.printStackTrace();
  12.                                 }
  13.                                 System.out.println(Thread.currentThread().getName() + "正在出售第"
  14.                                                 + (ticket--) + "张票");
  15.                         }
  16.                 }
  17.         }
  18. }
复制代码
  1. package com.kxg_09;

  2. /*
  3. * 实现Runnable接口
  4. */
  5. public class SellTicketDemo {
  6.         public static void main(String[] args) {
  7.                 // 创建自定义类对象
  8.                 SellTicekt st = new SellTicekt();

  9.                 // 创建线程
  10.                 Thread t1 = new Thread(st);
  11.                 Thread t2 = new Thread(st);

  12.                 // 设置线程名称
  13.                 t1.setName("窗口1");
  14.                 t2.setName("窗口2");

  15.                 // 启动线程
  16.                 t1.start();
  17.                 t2.start();
  18.         }
  19. }
复制代码
此时运行程序就会出现相同票卖多次和出现负数票的情况




5 个回复

倒序浏览
1.相同的票卖了多次
    CPU的一次操作必须是原子性的
2.出现负数票
    线程的随机性和延迟导致的

解决方式1:同步代码块
把多条语句操作共享数据的代码给包成一个整体,让某个线程在执行的时候,别人不能来执行
  1. package com.kxg_09;

  2. /*
  3. * synchronized(对象){
  4. *                 代码;
  5. * }
  6. *
  7. * 注意:同步代码块可以解决安全问题的根本原因在对象上,该对象如果锁一样的功能,别的线程不能进入。
  8. *                  这个对象可以是任意对象,最好是用本身this作为这个对象。
  9. *
  10. */
  11. public class SellTicekt implements Runnable {
  12.         private int ticket = 100;

  13.         @Override
  14.         public void run() {
  15.                 while (true) {
  16.                         synchronized (this) {
  17.                                 if (ticket > 0) {
  18.                                         try {
  19.                                                 Thread.sleep(100);
  20.                                         } catch (InterruptedException e) {
  21.                                                 e.printStackTrace();
  22.                                         }
  23.                                         System.out.println(Thread.currentThread().getName()
  24.                                                         + "正在出售第" + (ticket--) + "张票");
  25.                                 }
  26.                         }
  27.                 }
  28.         }
  29. }
复制代码



回复 使用道具 举报
方式2:同步方法
  1. package com.kxg_09;

  2. /*
  3. * synchronized关键字修饰方法
  4. * 锁对象是this
  5. */
  6. public class SellTicekt implements Runnable {
  7.         private int ticket = 100;

  8.         @Override
  9.         public synchronized void run() {
  10.                 while (true) {
  11.                         if (ticket > 0) {
  12.                                 try {
  13.                                         Thread.sleep(100);
  14.                                 } catch (InterruptedException e) {
  15.                                         e.printStackTrace();
  16.                                 }
  17.                                 System.out.println(Thread.currentThread().getName() + "正在出售第"
  18.                                                 + (ticket--) + "张票");
  19.                         }
  20.                 }
  21.         }
  22. }
复制代码


回复 使用道具 举报
本帖最后由 Kevin.Kang 于 2015-8-26 15:01 编辑

同步特点:
    前提:多个线程
    解决问题注意:多个线程使用的是同一个锁对象
同步好处:
    同步解决了多线程的安全问题
同步的弊端:
    当线程很多时,因为每个线程都会去判断同步上的锁,很消耗资源,降低程序的运行效率

回复 使用道具 举报
15225159271 来自手机 中级黑马 2015-8-5 11:28:14
报纸
好用功啊,比老师的视频代码你都给练习了
回复 使用道具 举报
向你致敬,实在是太用功了
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马