注:最近想研究多线程,网上搜索资料,发现多线程的资料很多,但是应用场景却很少,大部分都是指出了怎么开启多线程,却没有一个多线程结合实际场景的举例.比如说最经典的多线程就是多窗口卖票Model,但是实际工作中我们应该有service层参与啊,我们要处理业务才对.基于以上原因,本文简单提出一个多线程的应用场景,并进行测试,当然,之前并没有多线程实际的开发经验,只是这个demo经过测试之后可以用,在当前的场景下能够有效的提高效率,所以贴出来和大家分享,当然Demo中也有很多问题没有解决,希望大家(尤其是写过多线程业务的大腿)能够指出其中的不足,最好能举一个更加具体的多线程使用场景.感激不尽.
let’s go!
import java.util.List;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import cn.itcast.domain.User;
import cn.itcast.domain.Userdemo;
import cn.itcast.service.UserService;
import cn.itcast.service.UserdemoService;
public class ThreadUserTest implements Runnable {
// private int ticketCount = 100;// 总的票数,这个是共享资源,多个线程都会访问
Object mutex = new Object();// 锁,自己定义的,或者使用实例的锁
UserService userService = SpringContextUtil.getBean("userServiceImpl");
UserdemoService userdemoService = SpringContextUtil.getBean("userdemoServiceImpl");
List userList1 = userService.selectUserBySize(1);
List userList2 = userdemoService.selectUserBySize(1);
private int ticketCount = userList1.size();// 总的票数,这个是共享资源,多个线程都会访问
public void sellTicket() {
synchronized (mutex)// 当操作的是共享数据时,
// 用同步代码块进行包围起来,执行里面的代码需要mutex的锁,但是mutex只有一个锁。这样在执行时,只能有一个线程执行同步代码块里面的内容
{
if (ticketCount > 0) {
ticketCount--;
} else {
System.out.println("执行完成");
return;
}
}
}
public void run() {
while (ticketCount > 0)// 循环是指线程不停的去卖票
{
sellTicket();
/**
* 在同步代码块里面睡觉,和不睡效果是一样
* 的,作用只是自已不执行,也不让线程执行。sleep不释放锁,抱着锁睡觉。其他线程拿不到锁,也不能执行同步代码。wait()
* 可以释放锁 所以把睡觉放到同步代码块的外面,这样卖完一张票就睡一会,让其他线程再卖,这样所有的线程都可以卖票
*/
try {
// run方法注入service失败,service为null,目前理解为service为共有资源,不能线程共享,希望大腿们提出新的见解
/*
* User user1 = userService.selectUserById(ticketCount);
* Userdemo user2 = userdemoService.selectUserById(ticketCount);
*/
/*
* 当前这个场景代码实现不足的地方,第一,我现在的数据是能保证一一对应的,也就是说主键id是对应的
* 实际业务中,我们应该是有一边是遍历取出来,另一个需要根据id查出来,,查的这个业务就比较复杂了,是根据id直接查数据库(
* 这个方法怎么实现不知道,我的service线程里注入不进来 另一个就是在list里面查了:
* 这里涉及到的问题就是遍历list,查出id,然后list中再去除已经验证的id对应的user对象
* 有点绕,需要精心捋一捋逻辑
*
*/
User user1 = userList1.get(ticketCount);
Userdemo user2 = userList2.get(ticketCount);
if (!user1.getUserId().equals(user2.getUserId())) {
System.out.println(
"-------------------两张表数据不相同,用户id:" + user1.getId() + "---demo表id:" + user2.getId());
System.out.println("-------------------对比结果不同的线程名:" + Thread.currentThread().getName());
} else {
System.out.println("两张表数据相同" + Thread.currentThread().getName() + "----" + ticketCount);
}
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//补充:当前的循环中,应该根据id查询另一个list中的对应id的对象中的数据.后来思考这个问题,可以把list换成map,id为键,对象为value,这样作为被查询的list,应该能提高不小效率
这个是线程类的代码,是修改卖票demo来的,有一些参数名并没有改动.
ThreadUserTest usert = new ThreadUserTest();
Thread th1 = new Thread(usert, "窗口1");// 每个线程等其他线程释放该锁后,才能执行
Thread th2 = new Thread(usert, "窗口2");
Thread th3 = new Thread(usert, "窗口3");
Thread th4 = new Thread(usert, "窗口4");
th1.start();
th2.start();
th3.start();
th4.start();
启动线程就是上面这段代码,没什么特殊的,先说一下我的理解吧,有错误的地方欢迎指出:
start()调用的是run()方法,我们可以看到ruan里面就是一个循环,或者说就是一个for循环,启动几个线程就相当于启动了几个for循环,循环的数据是共享的.这样的话就能保证我的多线程启动之后,共同处理一块数据,也就是我们业务场景里面的那些订单.
- 问题
- 上面的代码漏洞比较多,大家都能看出来,我先提几个目前比较困惑的地方,大家一起来讨论讨论:
- 1.我上面写的这个demo,线程启动是写在了controller中,也就是需要项目启动,才能正常的创建线程.如果放在test里面,拿不到service,测试的时候会报空指针.在这里我的理解是项目没启动的话,spring容器没有把servicebean对象创建,所以拿不到,但是为什么其他的随便写个@autowired,service,调用service方法是没有问题的,难道只是线程里面 拿不到吗
- 2.有个困扰了好久的问题,查的资料比较少,就是线程实体run()和excute()两个方法里面为什么不能引入service.难道是service属于共享资源,不能被线程独享么,这一块到目前为止也不是很懂
多线程这边的问题比较多,尤其是共享资源的处理,现在还在研究中,不是特别明白,上面的demo只是为了实现这个业务场景而强行建立而来.如果有什么严重的逻辑问题,欢迎指出.
- * 多线程这边的问题比较多,尤其是共享资源的处理,现在还在研究中,不是特别明白,上面的demo只是为了实现这个业务场景而强行建立而来.如果有什么严重的逻辑问题,欢迎指出.因为小公司用不到多线程,也就没有练习的场景,大公司招人就需要会多线程的,这样只能逼着自学啊,,,,能力有限,写的不好的地方欢迎大家指正*