ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Java多线程demo

2020-10-27 17:00:34  阅读:255  来源: 互联网

标签:Java testUser 队列 demo 用户 线程 println 多线程 linkedQueue


近期考虑采用Java多线程实现给用户发短信的功能。自己做了一个简单的demo。

demo需求如下:通过界面输入用户名、密码、手机号,点击添加,即可实时的为该用户发一条短信。

image.png

实现过程如下:

1、参照文章https://blog.51cto.com/13082457/2542501搭建开发环境。

2、点击“添加”,通过ajax将参数传给后台。

$.ajax({
    type: "post",
    url:"/test/addTestUserToQue",
    contentType: "application/json;charset=UTF-8",//指定消息请求类型
    dataType: "json",
    data:JSON.stringify({
        "name":$("#name").val(),
        "password":$("#password").val(),
        "phone":$("#phone").val()
    }),
    success:function (result){
        if (result.msg=="OK"){
            console.log("用户添加队列成功!")
        }
    },
    error:function (result){
        console.log("data-msg:"+result.msg);
    }

注意:(1)contentType:"application/json;charset=UTF-8"这个必须加上,当时因为没有加,一直请求不到后台。

          (2)data属性的值是通过JSON.stringify()来转换的。

3、controller层-后台接收方法如下:

public JSONResult addTestUserToQue(@RequestBody TestUser testUser){
    testUserService.addTestUserToQue(testUser);
    return JSONResult.ok(testUser);
}

4、service层是具体的逻辑。会把该条用户信息加到对应的线程队列中。

public void addTestUserToQue(TestUser testUser) {
    System.out.println("添加用户进队列service--begin--");
    System.out.println("手机号最后一位:"+testUser.getPhone().substring(10));
    ConcurrentLinkedQueue<TestUser> linkedQueue = Xproducer.taskMap.get(testUser.getPhone().substring(10));
    if (linkedQueue==null){
        System.out.println("linkedQueue == null,需新建");
        linkedQueue = new ConcurrentLinkedQueue<TestUser>();
    }
    linkedQueue.add(testUser);
    Xproducer.taskMap.put(testUser.getPhone().substring(10),linkedQueue);
    System.out.println("添加用户进队列service--end--");
}

5、新建一个线程类,实现发短信的效果。该线程类中需要定义一个线程池,线程池必须是静态变量,作为类的成员。

public static ConcurrentHashMap<String, ConcurrentLinkedQueue<TestUser>> taskMap = new ConcurrentHashMap<>();

     线程类里需重写run方法。线程实现的效果就是不断的从线程池队列中取出用户信息,逐条给用户发短信。

while (true){
   
    ConcurrentLinkedQueue<TestUser> linkedQueue = taskMap.get(mode);
    if(null!=linkedQueue&&linkedQueue.size()>0) {
      System.out.println("linkedQue不空,取出用户手机号,准备发短信");
      TestUser testUser = linkedQueue.poll();
      if (null != testUser){
        System.out.println("给用户" + testUser.getName() + "发短信完毕");
      }
    }else {
       ConcurrentLinkedQueue<TestUser> linkedQueue = taskMap.get(mode);
      if(null!=linkedQueue&&linkedQueue.size()>0) {
        TestUser testUser = linkedQueue.poll();
        if(null!=testUser){
          System.out.println("给用户"+testUser.getName()+"发短信");
        }
      }else{
        Thread.sleep(1000);
      }
    }
}

6、service层实现接口InitializingBean。通过重写afterPropertiesSet()方法,实现程序预加载。预加载时开启多个线程类,相当于做一个初始化。

for (int i=0; i<Xproducer.initNum;i++){
            Xproducer xproducer = SpringUtil.getBean(Xproducer.class);
            xproducer.setMode(i+"");
            xproducer.setThreadName("thread"+i);
            Thread thread = new Thread(xproducer);
            thread.start();
}

功能执行过程解析:

启动项目之后,系统加载service之后,会自动调用afterPropertiesSet()方法,开启多个线程类Xproducer。此时每个线程都会执行run方法。此时每个线程里面的线程队列都是空的,所以每个线程都会执行Thread.sleep()方法,处于阻塞状态。

如果此时通过界面输入一条用户信息,点击“添加”之后,系统会把该用户信息添加到对应的线程中的队列中。例如添加到了0号线程的线程队列。那么0号线程此时再次判定队列不为空时就会执行相应的发送短信的功能。


本功能的重点在于service实现了接口InitializingBean的afterPropertiesSet()方法。该方法中,通过getBean方法可以得到线程类。

需要注意的是:SpringUtil类必须在service类之前被加载,否则getBean()会报NUll的错误。通过在启动类中添加扫描注解来实现。如下,我们把SpringUtil类放到jar文件夹下,那么系统启动的时候,就会先扫描jar下的文件,然后再扫描com下面的文件,保证SpringUtil先于Service之前被加载

@SpringBootApplication(scanBasePackages = {"jar","com"})


标签:Java,testUser,队列,demo,用户,线程,println,多线程,linkedQueue
来源: https://blog.51cto.com/13082457/2544451

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有