首页 > 代码库 > 多线程中共享变量——CCF总决赛试题

多线程中共享变量——CCF总决赛试题

题目要求

数据格式

Q 系统的输入为纯文本格式的文件,由若干行组成,每一行由城市编号、年龄、收入组成,相邻两项之间用一个空格分隔。以下是输入的一个片段:

1001 20 12000

1001 50 24200

1020 30 30000

其中,城市编号是四位数(第一位不为 0),年龄与收入为整数类型。

查询描述

Q 系统需要实现以下三个常用的查询功能:

  • Q1: 查询城市 X 某个年龄段的平均收入;

 

  • Q2: 查询城市 X 的收入最高的前 K 位的收入;

 

  • Q3: 分别查询某些城市某一年龄段收入的中位数。

一、下面的程序使用多线程比单线程快了将近一倍。

下面代码简化了输入过程,让输入的数据提前确定好,便于看时间的效率。

import java.io.*;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Scanner;
class My_Thread implements Runnable{
    public File file=new File("src/xian/chen01/city.txt"); /*city.txt中存放数据*/
    public BufferedReader reader = null;
    public List<Integer> list=null;
    public List<Integer> n_list=null; /*List方便排序*/
    public int line=0;
    public int n_line=0;
    public int k=50;
    public String x_number="1001";
    public String n_number="1001";
    public int n_age=20;
    public BigInteger age=null;
    public int back=0;
    public long t1=0;
     public My_Thread(){
         t1=System.currentTimeMillis();
        try{
         reader = new BufferedReader(new FileReader(file));
         list=new ArrayList<Integer>();
         n_list=new ArrayList<Integer>();
         age=new BigInteger("0");
        }catch(Exception e){}
    }
    @Override
    public void run() {  
/*此处代码是核心,加锁避免了java.io.IOException: Stream closed 问题*/
        synchronized (this) {
            if(back==0)
                hui();   /*取出文件的内容*/ 
            else
            {    if(back==1)
                  print();   /*打印结果*/
                else
                    return ;
            }
        }    
    }
    public synchronized void hui (){
        try{
        //long t1=System.currentTimeMillis();
        
         String tempString = null;
         while ((tempString =reader.readLine())!=null) {
             String str[]=tempString.split(" ");
             if(x_number.equals(str[0]))
             {
                 age=age.add(new BigInteger(str[1]));
                 int a=Integer.parseInt(str[2]);
                 list.add(a);
                 line ++ ;
             }    
             if(n_number.equals(str[0])&&(n_age+"").equals(str[1]))
             {
                 n_list.add(Integer.parseInt(str[2]));
                 n_line++;
             } 
         }
         reader.close();
         back=1;
        }catch(Exception e){
            System.out.println(e);
        }
    };
    public synchronized void print(){
         Comparator<Integer> comparator = new Comparator<Integer>()
         {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2-o1;   /*降序*/
            }
          };
         if(line>0)
         {
           age=age.divide(new BigInteger(line+""));
           Collections.sort(list,comparator);
           System.out.println("该城市的总人数:"+line);
           System.out.println("list的大小:"+list.size());
           System.out.println("该城市的平均年龄:"+age);
           System.out.print("该城市的前k位收入是:");
           for(int i=0;i<k&&i<list.size();++i)
           System.out.print(list.get(i)+"、");
           System.out.println();
         }
         else
             System.out.println("该城市编号不存在");
         /*下面是求某个城市的年龄段的中位数收入*/
         System.out.print("编号n城市中位数是:");
         if(n_line>0)
         {
             Collections.sort(n_list,comparator);
             if(n_line%2==1)
                 System.out.println(n_list.get(n_line/2));
             else
             {
        System.out.println((n_list.get(n_line/2)+n_list.get((n_line-1)))/2);
             }
         }else
             System.out.println("编号n城市对应的年龄不存在");
         back=2;
        System.out.println("时间:"+(System.currentTimeMillis()-t1));
    };
};
public class Scoket_Q_City_Query2 {
public static void main(String[] args) throws Exception {
    
  My_Thread thread=new My_Thread();
  new Thread(thread).start();
  new Thread(thread).start();
  new Thread(thread).start();
  new Thread(thread).start();
  new Thread(thread).start(); 
};
}

运行结果:54毫秒

技术分享

二、下面是仅仅是一个单线程实现(也可以不建立单线程,只在main主线程实现也可以)

import java.io.*;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Scanner;
class MyThread implements Runnable{
    @Override
    public void run() {
        hui();
    }
    public synchronized void hui (){
        try{
        long t1=System.currentTimeMillis();
         Scanner sc=new Scanner(System.in);
         Comparator<Integer> comparator = new Comparator<Integer>()
         {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2-o1;   /*降序*/
            }
          };
         System.out.print("输入X城市的编号:");
         String x_number=null;
                 //sc.next();
         x_number="1001";
         System.out.print("收入X城市的k值:");
         int k=50;
                 //sc.nextInt();
         System.out.print("输入某个n城市的编号:");
         String n_number="1001";
                 //sc.next();
         System.out.print("输入n城市的某个年龄:");
         int n_age=20;
                 //sc.nextInt();
         sc.close();
         File file=new File("src/xian/chen01/city.txt");
         BufferedReader reader = null;
         String tempString = null;
         BigInteger age=new BigInteger("0");
         int line =0;
         int n_line =0;
         List<Integer> list=new ArrayList<Integer>();
         List<Integer> n_list=new ArrayList<Integer>();
         reader = new BufferedReader(new FileReader(file));
         while ((tempString =reader.readLine())!=null) {
             String str[]=tempString.split(" ");
             if(x_number.equals(str[0]))
             {
                 age=age.add(new BigInteger(str[1]));
                 int a=Integer.parseInt(str[2]);
                 list.add(a);
                 line ++ ;
             }
             if(n_number.equals(str[0])&&(n_age+"").equals(str[1]))
             {
                 n_list.add(Integer.parseInt(str[2]));
                 n_line++;
             } 
         }
         reader.close();
        
         if(line>0)
         {
           age=age.divide(new BigInteger(line+""));
           Collections.sort(list,comparator);
           System.out.println("该城市的总人数:"+line);
           System.out.println("list的大小:"+list.size());
           System.out.println("该城市的平均年龄:"+age);
           System.out.print("该城市的前k位收入是:");
           for(int i=0;i<k&&i<list.size();++i)
           System.out.print(list.get(i)+"、");
           System.out.println();
         }
         else
             System.out.println("该城市编号不存在");
         /*下面是求某个城市的年龄段的中位数收入*/
         System.out.print("中位数是:");
         if(n_line>0)
         {
             Collections.sort(n_list,comparator);
             if(n_line%2==1)
                 System.out.println(n_list.get(n_line/2));
             else
             {
                 
                 System.out.println((n_list.get(n_line/2)+n_list.get((n_line-1)/2))/2);
             }
         }else
             System.out.println("编号n城市对应的年龄不存在");
         System.out.println("运行时间:"+(System.currentTimeMillis()-t1));
        }catch(Exception e){}
    };
};
public class Scoket_Q_City_Query {
public static void main(String[] args) throws Exception {
    
  MyThread thread=new MyThread();
  Thread th=new Thread(thread);
  th.start();
};
}

时间:84毫秒

技术分享

 

多线程中共享变量——CCF总决赛试题