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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 张综 中级黑马   /  2012-11-15 23:23  /  1851 人查看  /  4 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 张综 于 2012-11-16 20:08 编辑

一个模拟售票系统,用到了多线程。先写了一个票库,也就是类名为票库的类,其中写了三个方法,一个是set方法,用来往里传入票数。也就是总票数。一个是get方法。获取还剩多少张票。一个是出票的方法。就是把票库里的票减减,然后写一个Thread类的子类。调用出票方法。然后创建了四个窗口的线程对象。一大印,就会先打出四个100,我知道是刚开始因为四个线程同时启动导致的。请问,怎么解决这个问题。
上代码。。
package cn.itcast.thread.piao.two;

public class Test1 {
        public static void main(String[] args) {
                PiaoKu pk = new PiaoKu(100);
                Thread th1 = new ChuangKouThread(pk, "a");
                Thread th2 = new ChuangKouThread(pk, "b");
                Thread th3 = new ChuangKouThread(pk, "c");
                Thread th4 = new ChuangKouThread(pk, "d");
                th1.start();
                th2.start();
                th3.start();
                th4.start();
        }
}

/*
* 窗口类
* 有一个票库属性
* 任务中循环出票
* 当发现票数小于等于0时,结束任务
*/
class ChuangKouThread extends Thread {
        private PiaoKu pk;
        
        public ChuangKouThread(PiaoKu pk, String name) {
                super(name);
                this.pk = pk;
        }
        
        public void run() {
                while(true) {
                        int cnt = pk.getCount();
                        if(cnt <= 0) {
                                break;
                        }
                        try {
                                Thread.sleep(20);
                        } catch(InterruptedException e) {}
                        String name = Thread.currentThread().getName();
                        System.out.println(name + ": " + cnt);
                        pk.chuPiao();
                }
        }
}

class PiaoKu {
        private int cnt;
        
        public PiaoKu(int cnt) {
                this.cnt = cnt;
        }
        
        // 返回当前票库的剩余票数
        public int getCount() {
                return cnt;
        }
        
        // 出票方法,就是把票数减减
        public void chuPiao() {
                this.cnt--;
        }
}


点评

售票多窗口,会不会出席那多线程安全问题呢  发表于 2012-11-16 09:10

评分

参与人数 1技术分 +1 收起 理由
古银平 + 1 赞一个!

查看全部评分

4 个回复

倒序浏览
问题的原因:
        当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,
        另一个线程参与进来执行。导致共享数据的错误。
解决办法:
        对多条操作共享数据的语句,只能让一个线程都执行完。在执行过程中,其他线程不可以参与执行。
Java对于多线程的安全问题提供了专业的解决方式。
就是同步代码块。
synchronized(对象)
{
        需要被同步的代码
}
同步的前提:
1,必须要有两个或者两个以上的线程。
2,必须是多个线程使用同一个锁。

        public void run() {
                while (true) {
                        synchronized (pk) {              //   在得到共享数据之前加上锁
                                int cnt = pk.getCount();
                                if (cnt <= 0) {
                                        break;
                                }
                                try {
                                        Thread.sleep(20);
                                } catch (InterruptedException e) {
                                }
                                String name = Thread.currentThread().getName();
                                System.out.println(name + ": " + cnt);
                                pk.chuPiao();
                        }
                }
        }

评分

参与人数 1技术分 +1 收起 理由
古银平 + 1 赞一个!

查看全部评分

回复 使用道具 举报
1.楼主创建线程采用的是继承Thread类的方法,所以才会出现打印四个100的现象。
2.解决方法是,可以将票数定义为static,让四个线程共享数据。
  但这种方法并不合理,因为静态的生命周期很长,会占用内存空间。
3.最好的解决方式是,采用第二种创建线程的方式,步骤如下,
(1)定义类实现Runnable接口
(2)覆盖Runnable中的run方法
(3)通过Thread类建立线程对象
  (4)将Runnable接口的子类对象作为实际参数传递给Thread类的构造函数
(5)调用Thread类中的start方法开启线程
4.楼主试一下,改过后应该就可以了

评分

参与人数 1技术分 +1 收起 理由
古银平 + 1 你还忘了一个多线程安全问题

查看全部评分

回复 使用道具 举报
刘菲 发表于 2012-11-16 08:47
1.楼主创建线程采用的是继承Thread类的方法,所以才会出现打印四个100的现象。
2.解决方法是,可以将票数定 ...

恩,应该要加同步,谢谢提醒!
回复 使用道具 举报
这题如何使用同步函数来解决安全问题呢,
然后implements Runable之后在main方法里面如何改呢?
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马