在开始之前我想纠正一个错误,网上的错误。

网上说多线程数要与cpu数有一定规律,比如说什么最佳线程数应该等于核数*2等说法,对于这种说法

我做了测试,我是这么测试的

第一次10个线程处理2000条数据(调用接口),结果:数据一般;

第二次50个线程处理2000条数据(调用接口),结果:数据快了;

第三次100个线程处理2000条数据(调用接口),结果:数据更更快了,基本上几秒钟完事。

第四次200个线程处理2000条数据(调用接口),结果:数据更更更快了;基本上一下子完事。

就上面的测试结果,我感觉网上说的冒失不对啊,如果只考虑处理速度不考虑其他问题的话,我觉得线程足够多就行,与cpu什么的没什么关系啊(可能,我测试的有问题,望高手给与指点)

另外,以前我对多线程同步总是不知道什么情况下需要去做同步加锁处理,在经过鄙人的反复测试后,个人认为:只有在多个线程共享一个static的资源时才有必要考虑同步,那问题又来了,

既然有大量并发并且加了锁,那就要考虑死锁问题,这里使用的是notify

完成的功能很简单:
    每1分钟去一个表里查询list数据并放入java的queue队列里(不是MQ,就是一个java队列)。
    然后唤起线程池,启动10个线程来取出queue里的数据并打印出来。


1.监听器
(1)web.xml里
<listener>
    <listener-class>com.sf.partner.mgt.context.APIListener</listener-class>
 </listener>
(2)代码 
public class APIListener extends HttpServlet implements ServletContextListener {
    private static final long serialVersionUID = 4401296288922971302L;
    public APIListener() {
    }
    private java.util.Timer timer = null;//定义一个定时器
    public void contextInitialized(ServletContextEvent event) {
        timer = new java.util.Timer(true);
            //TaskQuery自定义定时器,查询list并放入queue队列里
        timer.schedule(new TaskQuery(event.getServletContext()), 
                0, 60*1000);// 1000毫秒*60=1分钟
        event.getServletContext().log("已经添加任务调度表-定时器");
    }

    public void contextDestroyed(ServletContextEvent event) {
        timer.cancel();
        event.getServletContext().log("定时器销毁");
    }

}

2.TaskQuery代码:
  public class TaskQuery extends TimerTask {
    public static Queue<Object> queue;//Queue是java自己的队列List,具体可看API,是同步安全的.

//这里在介绍一个很好用又强大的线程安全的Map==》ConcurrentHashMap (具体可看API)

    static {
      queue = new ConcurrentLinkedQueue<Object>();
    }
    private static boolean isRunning = false;
    private ServletContext context = null;

   private String lock1 = "";

    public TaskQuery() {
    }

    public TaskQuery(ServletContext context) {
        this.context = context;
    }
    public void run() {

    synchronized (lock1) {       

     if (!isRunning) {
            isRunning = true;
            context.log("开始执行查询并放入queue队列");
            queryList();
            context.log("查询并放入queue队列结束");
            ThreadPool.createThreadPool();//唤起线程池
            isRunning = false;
        } else {
            context.log("上一次任务执行还未结束");
        }

        lock1.notify();//必须要加这个,不然有时会死锁
    }

    }
      /*
    *queue 和 这个queryList()方法都可以根据具体业务提取成单独的java文件
    */
      public void queryList() {
     //list就是从数据库里查询的结果
      for(String str : list) {
              queue.offer(str);//向队列添加数据
      }
    } 
}
3.ThreadPool线程池代码:
(我以前也没搞过多线程,这个是我在网上看的,
然后自己改改,测了下觉得还行,但是肯定是菜鸟的手笔,说以欢迎大家拍砖) (这里需搞清楚线程对象与线程的区别):
public class ThreadPool {
    public static void createThreadPool() {
        Random random = new Random();
        /**
         * 产生一个 ExecutorService 对象,这个对象带有一个大小为 poolSize 的线程池, 若任 务数量大于 poolSize,任务会被放在一个 queue 里顺序执行。这里开启10个线程对象,放入线程池
         */
        ExecutorService executor = Executors.newFixedThreadPool(10);
        int waitTime = 500;
        if (TaskQuery.queue.size() > 0) {
    //这个for循环里的代码就是从线程池里获得线程对象,并执行多线程操作
         for (int i = 0; i < TaskQuery.queue.size() + 2; i++) {
            int time = random.nextInt(1000);
            waitTime += time;
            Runnable runner = new ExecutorThread(TaskQuery.queue.poll(),
             time);
            executor.execute(runner);
          }
        }
        try {
          executor.shutdown();// 只是将线程池置于关闭状态,不接受新任务,对正在运行的任务不影响
          executor.awaitTermination(waitTime, TimeUnit.MILLISECONDS);
        } catch (InterruptedException ignored) {
        }
    }
}
/*
*线程类实现Runnable接口
*/
class ExecutorThread implements Runnable {
    private Object obj;
    private int delay;

    public ExecutorThread(Object obj, int delay) {
        this.obj = obj;
        this.delay = delay;
    }

    public void run() {
           /*
        *这里就是线程需要处理的业务了,可以换成自己的业务
        */
        try {
        if(obj != null) {
         System.out.println("运行的线程数"+Thread.activeCount());
         System.out.println((obj.toString());
        }
            Thread.sleep(delay);
        } catch (InterruptedException ignored) {
        }
    }
}

到这里这个小例子我算写完了,希望大家拍砖指教,希望,千万别出什么幺蛾子啊