请各位高手指教,问题详情如下:我是用eclipse写的java程序,可以同时连接多个读卡器,对多张卡同时执行写卡操作。我对每个读卡器创建了一个线程,程序开始后,多个线程同时启动,轮流排队对每个读卡器进行写卡操作,写卡命令会在屏幕上显示,所以多张卡会在差不多的时间点写完。
问题是我的程序同时写5张卡基本上没什么问题,但是同时写6张以上的卡时在写到40分钟左右的时候,CPU的使用率就逐渐累加,从10%到20%,然后到40%-50%,之后就会死掉了,没有任何错误提示,都是在发了一条命令后不显示返回数据,然后程序的UI就不动了,但是电脑上的其他程序都是正常的。程序死掉时偶尔会有卡片已经写卡成功,但多数情况下是所有的卡片都没有完成写卡。eclipse中的VM参数为-Xmx1024m,运行程序的电脑内存为2G。我把程序打包成可执行的jar文件,copy到别的机器上运行。
我自己的机器是2G内存,其他配置比较高,有时候能同时写成功6张和6张以上的卡,但是在另外一台老机器上就不行,那台机器的内存也是2G,但是其他的配置就比较低了。读卡器都是连在一个带电源的USB hub上,所以排除了USB口供电不足的问题。
还有写卡的数据量挺大的,每张卡要写4块程序区,1块数据区,每块区域都是从0000到FFFF,每条命令写0x80个字节,所以每张卡要发2500多次命令。
我的程序中没有对线程做终止处理,也没有调用isAlive()之类的函数判断线程是否还处于活动状态.

解决方案 »

  1.   

    关键的函数如下:main()如下:        public static void main(String[] args) {
                    try{
                            UIManager.setLookAndFeel(
                                            UIManager.getSystemLookAndFeelClassName());
                    }catch(Exception e){
                            throw new RuntimeException(e);
                    }
                    // TODO Auto-generated method stub
                    SwingUtilities.invokeLater(new Runnable() {
                            public void run() {
                                    WriteCardByPCSCMain application = new WriteCardByPCSCMain();
                                    application.getJFrame().setVisible(true);
                            }
                    });
            }
    调用线程的函数:
            private List<ExecuteThread>  executeThreads = new ArrayList<ExecuteThread>();          public JButton getExeBtn() {
                    if (exeBtn == null) {
                            exeBtn = new JButton("Execute");
                            exeBtn.setBounds(new Rectangle(190, 332, 90, 30));
                            exeBtn.setBackground(Color.green);
                            exeBtn.addActionListener(new ActionListener() {
                                    public void actionPerformed(ActionEvent e) {
                                            exeBtn.setEnabled(false);
                                            exeBtn.setBackground(Color.red);
                                            refreshBtn.setEnabled(false);
                                            //connBtn.setEnabled(false);
                                            countNum = 0;
                                            errorNum=0;
                                            AddorClearTabPane addorclearTabPane =new AddorClearTabPane();                                                                        if(listModel.size() == 0){
                                                    JOptionPane.showMessageDialog(null,"没有连接读卡器,请确认。");
                                                    exeBtn.setEnabled(true);
                                                    refreshBtn.setEnabled(true);
                                                    return;
                                            }
                                            
                                            if(executeThreads.size() > 0)                                                                
                                            TabPane.clearRunLog(executeThreads.size());
                                            else{
                                            String readerName;
                                            int num = 0;
                                            addorclearTabPane.clearTab(logTabbedPane);
                                             for(int i = 0;i < 10;i++){                                         
                                                     if(recReaderName ==null 
                                                                     || recReaderName.length() ==0)
                                                             continue;                                                         
                                                     readerName = recReaderName;
                                                     String temp =listModel.get(i).toString();
                                                addorclearTabPane.addTab(logTabbedPane,num,temp.substring(temp.indexOf("--")+2));
                                                        recordReaderName.put(readerName,num);
                                                        num++;
                                             }
                                    }
                                    
                                     
                                            if(recordReaderName.size() == 0){
                                                    exeBtn.setBackground(Color.green);
                                                    exeBtn.setEnabled(true);
                                                    return;
                                            }
                                            
                                    if(seqCount == 0){
                                            if(!InitialCard()){
                                                    exeBtn.setBackground(Color.green);
                                                    exeBtn.setEnabled(true);
                                                    return;
                                            }
                                            }
                                    
                                    end();
                                    executeThreads.clear();
                                    
                                            for (int i = 0; i <recordReaderName.size(); i++)
                                                    executeThreads.add(new ExecuteThread(recReaderName));        
                                            for (ExecuteThread workerThread : executeThreads) {
                                                    workerThread.start();
                                            
                                            }
                                                    
                                            
                                    }                        
                            });
                    }
                    return exeBtn;
            }
      

  2.   

    线程实现函数:
            public class ExecuteThread extends Thread {
                    String readerName;                public ExecuteThread(String name) {
                            readerName = name;
                    }
                    public void run() {
                            execute();
                    }
                    
                    private  synchronized void execute(){
                            countNum ++;
                            if(!connPCSCReader(readerName))
                                    return;
                            
                            //send "verify" command
                            verifyCard(readerName);
                            if(!flag)
                                    return;
                            
                            //Erase 
                            eraseCard(readerName);
                            if(!flag)
                                    return;                        
                            
                            //send Pflash Base and Write                
                            for(int i = 2; i < 6; i++){
                                    writePflash(readerName,i);
                                    if(!flag)
                                            return;
                            }
                                            
                            TabPane.writeRunLog(readerName, recReaderName, "Write data now,please wait...", "green");
                            //verify
                            verifyCard(readerName);
                            if(!flag)
                                    return;
                            updataDflash(readerName);
                            
                            String retStr;         
                            TabPane.writeRunLog(readerName, recReaderName, "\nPflash Base:","blue");
                            String cmd = "00 30 00 02 00";
                            TabPane.writeRunLog(readerName, recReaderName, "   "+cmd,"black");
                            retStr = sendCMD(readerName,cmd);
                            if(!verify(readerName,retStr))
                                    return;                
                            
                            TabPane.writeRunLog(readerName, recReaderName,"Pflash Write:" ,"blue");
                            TabPane.writeRunLog(readerName, recReaderName,"00 38 00 00 "+length,"black");
                            TabPane.writeRunLog(readerName, recReaderName,chipData02.get(0),"black");
                            retStr = sendCMD(readerName,"00 38 00 00 "+length + chipData02.get(0));
                            if(!verify(readerName,retStr))
                                    return;
                            
                            retStr = closePCSCReader(readerName);
                            if(retStr.indexOf("46 61 69 6C") != -1 || 
                                            retStr.indexOf("Fail") != -1){
                    //                JOptionPane.showMessageDialog(null, readerName+"\n断开卡失败.");
                                    TabPane.writeRunLog(readerName, recReaderName," 断开卡失败"+readerName,"red");
                                    return;
                            }                        if(!connPCSCReader(readerName))
                                    return;//                        
                            //CheckSum
                            TabPane.writeRunLog(readerName, recReaderName, "CheckSum:","black");
                            cmd = "A0 BA 00 00 04"+checkSum;
                            TabPane.writeRunLog(readerName, recReaderName,"   "+cmd,"black");
                            retStr = sendCMD(readerName,cmd);
                            if(!verify(readerName,retStr)){
                                    return;
                            }                
    //                        
                            retStr = closePCSCReader(readerName);
                            if(retStr.indexOf("46 61 69 6C") != -1 || 
                                            retStr.indexOf("Fail") != -1){
                                    //JOptionPane.showMessageDialog(null, readerName+"\n断开卡失败.");
                                    TabPane.writeRunLog(readerName, recReaderName," 断开卡失败"+readerName,"red");
                                    return;
                            }
                            
                            if(!connPCSCReader(readerName))
                                    return;
    //                        
                            //INS: Verify ADM4
                            TabPane.writeRunLog(readerName, recReaderName, "Verify ADM4:","blue");
                            cmd = "A020000E08"+adm4; //S9000
                            TabPane.writeRunLog(readerName, recReaderName, "   "+cmd,"black");
                            retStr = sendCMD(readerName,cmd);
                            if(!verify(readerName,retStr))
                                    return;
                    
                            //INS: Verify ADM1 
                            TabPane.writeRunLog(readerName, recReaderName, "Verify ADM1:","blue");
                            cmd = "A0 20 000B 08 0000000000000000"; //S9000
                            TabPane.writeRunLog(readerName, recReaderName, "   "+cmd,"black");
                            retStr = sendCMD(readerName,cmd);
                            if(!verify(readerName,retStr))
                                    return;
                    
                            //INS: Verify CHV2  
                            cmd = "A0 20 0002 08 35363738FFFFFFFF"; //S9000 
                             retStr = sendCMD(readerName,cmd);
                            if(!verify(readerName,retStr))
                                    return;
                            
                            //INS: Select 3F00
                             cmd = "A0A40000023F00" ;//S9F16/)
                            retStr = sendCMD(readerName,cmd);
                            if(!verify(readerName,retStr))
                                    return;
                            
                            //ICCID
                             cmd = "a0a40000023f00";
                            retStr = sendCMD(readerName,cmd);
                            if(!verify(readerName,retStr))
                                    return;
            
                            cmd = "a0a40000022FE2" ;  
                            retStr = sendCMD(readerName,cmd);
                           if(!verify(readerName,retStr))
                                    return;
            
                            
                            String strTemp="";
                            if(seqCount == 0){
                                            cmd = "A0D600000A" + seqence;
                            }else{
                                    int countNo = Integer.parseInt(seqence.substring(12),16) + seqCount;
                                    strTemp = Integer.toHexString(countNo).toUpperCase();
                                    while(strTemp.length() < 8)
                                            strTemp = "0" + strTemp;
                                    cmd = "A0D600000A" + seqence.substring(0,12)+strTemp;                        
                            }
                            seqCount ++;
                            TabPane.writeRunLog(readerName, recReaderName, "   "+cmd, "black");
                            retStr = sendCMD(readerName,cmd);
                            if(!verify(readerName,retStr)){
                                    seqCount --;
                                    return;
                            }
                            strTemp = cmd.substring(10);
                            TabPane.writeRunLog(readerName, recReaderName, "Read seqence:", "blue");
                            cmd = "A0 B0 00 00 0a";
                            TabPane.writeRunLog(readerName, recReaderName, "   "+cmd, "black");
                            retStr = sendCMD(readerName,cmd);
                            if(!verify(readerName,retStr)) {
                                    seqCount --;
                                    return;
                            }
                            retStr = retStr.replace(" ", "");
                            if(retStr.indexOf(strTemp) != -1)
                            {
                                    String ICCIDret = retStr.toString();
                                    ICCIDret = ICCIDret.substring(0,20);
                            //        JOptionPane.showMessageDialog(null, readerName + "\nISIM卡:"+strTemp+"制作完成.");
                                    TabPane.writeRunLog(readerName, recReaderName," ICCID:"+ICCIDret,"green");
                            TabPane.writeRunLog(readerName, recReaderName," SIM卡制作完成"+readerName,"green");
                            }
                            else {
                                    seqCount --;
                            }
                            retStr = closePCSCReader(readerName);
                            if(retStr.indexOf("46 61 69 6C") != -1 || 
                                            retStr.indexOf("Fail") != -1){
                            //        JOptionPane.showMessageDialog(null, readerName+"\n断开卡失败.");
                                    TabPane.writeRunLog(readerName, recReaderName,"断开卡失败,这不是个错误,SIM卡已制作完成"+readerName,"green");
                                    return;
                            }
                            
                            if(countNum == recordReaderName.size()) {
                                    exeBtn.setBackground(Color.green);
                                    exeBtn.setEnabled(true);
                            }                        
                    }
      }
      

  3.   

    1. 把线程实现的execute()方法前的synchronized去掉
    2. 把写日志的部分改为通过Piped Stream实现
      

  4.   

    csdn的朋友发帖都不知道把代码格式化一下的。
      

  5.   

    1、把synchronized去掉多个线程之间写卡不会写乱了吧?
    2、现在写log的函数会占用很多资源吗?多谢!
      

  6.   

    分析了你的需求,你用多线程并发执行,但没有数据共享,不要用同步,加了同步反而会影响效率 synchronized去掉后试试看有没有问题。至于你的日志是否用Piped Stream我没想法。
      

  7.   

    你传了 readerName进去,不会乱的,各写各的。
      

  8.   

    觉得不是代码的问题,是你机器的问题,MyEclipse很吃内存,我以前也是用2g内存,根本不顶用,写代码时候很卡,后来我换了3g的就好了。
      

  9.   

    主要是CPU占用率高,我觉得程序是有问题的
      

  10.   

    每个卡由一个线程负责,那么不会写乱。
    UI部分会出现并发问题,所以要使用Pipe,交给主线程轮询处理。
      

  11.   

    刚才把synchronized去掉试了6张卡,有4张卡在45分钟以前写完,1张卡出现了写卡错误,最后一张还是在50分钟左右的时候死掉了。如果我把写log的程序去掉,会有帮助吗?
      

  12.   

    多谢各位了,问题解决了,就是把synchronized去掉,又把写log的函数隐掉就可以了,多谢!马上结贴给分。