Java单线程多实例和多线程多实例
最近写了一个程序,是采用多线程往redis里面写入数据,想统计一下一共写了多少条数据,于是用了一个static的全局变量count来累加,这块代码抽象出来就是这样的:
public class MultiThread implements Runnable {
private String name;
private static Integer count = 0; public MultiThread() {
} public MultiThread(String name) {
this.name = name;
} public void run() {
for (int i = 0; i < 5; i++) {
//模拟写入redis的IO操作消耗时间
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
} //累加写入次数
count++;
System.out.println(name + "运行 " + i + " 写入条数:" + count);
}
} public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(new MultiThread("Thread"+i)).start();
}
}
}
启动了100个线程,每个线程写入5次,预计结果应该是500,但是实际结果是这样的:
分析了原因,应该是因为count++不是原子操作,这句代码实际上是执行了3步操作:1,获取类变量count值。2,count+1。3,将count+1后的结果赋值给类变量count。在这3步中间都有可能中断执行其他线程。这样比如线程1先获取了count=0,这时候切换到线程2,线程2获取了count=0,然后又切换到线程1,线程1执行count++=1并修改了类变量count=1,之后又切换到线程2,线程2对之前它获取到的count=0执行count++=1并修改类变量count=1。问题出现了,明明有两个线程对count累加了两次,但是由于count没有加锁,最终类变量只加了1。
根据分析修改程序成下面这样,给count加了同步,将上面代码中第22行的"count++"改为了:
synchronized (count) {
count++;
}
这次运行前两次都正常显示了500,但是多运行几次发现个别时候仍然有问题:
再次分析原因,分析不出来了,开始各种修改各种试,终于成功试验出了正确代码,将count++移到外面,封装到类的静态同步方法里:
public class MultiThread implements Runnable {
private String name;
private static Integer count = 0; public MultiThread() {
} public MultiThread(String name) {
this.name = name;
} public void run() {
for (int i = 0; i < 5; i++) {
//模拟写入redis的IO操作消耗时间
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
} //累加写入次数
countPlus();
System.out.println(name + "运行 " + i + " 写入条数:" + count);
}
} private static synchronized void countPlus(){
count++;
} public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
new Thread(new MultiThread("Thread"+i)).start();
}
}
}
这次运行多次结果均是正常的,为了确保结果正确,又把线程数改为1000试验了多次,结果也是正确的(5000,不过要好好找找了,因为countPlus()和sysout在多个线程里会交错执行,这个5000不一定会出现在什么位置...从最后一行往前找吧...)。
看着这个运行结果,基本能猜到原因了,原因就出在这一句:
new Thread(new MultiThread("Thread"+i)).start();
这里为每个线程new了一个对象,所以之前的
synchronized (count) {
count++;
}
的作用范围是同一个对象的多个线程,也就是说它能够确保Thread1对象的多个线程访问count的时候是同步的,而实际上我们是多线程多实例,每个线程都对应一个不同的对象,所以这句代码实际上是不能起到同步count的作用的。
最新文章
- git log命令全解析,打log还能这么随心所欲!
- Autodesk 最新开发技术研讨会-北京-上海-武汉-成都-西安-PPT下载
- PDA手持移动POS销售开单软件(网络版)、PDA手持设备小票机
- 关于UID和GID的创建、修改、删除;简要举例
- css构造块级元素
- <;marquee>;属性详解
- Python15-day1课后作业
- hdu 4496 (并差集)
- EventLog实现事件日志操作
- Linux sed命令删除指定行
- Strange Country II 暴力dfs
- FTP下载帮助类
- 语音激活检测(VAD)--前向神经网络方法(Alex)
- Web 小案例 -- 网上书城(三)
- day16——函数式编程和内置函数
- Mysql出现(10061)错误提示的暴力解决办法
- OkHttp 入门篇
- [洛谷P3948]数据结构 题解(差分)
- Shiro笔记(一)基本概念
- BZOJ3600:没有人的算术
热门文章
- BZOJ5322:[JXOI2018]排序问题——题解
- BZOJ2597 [Wc2007]剪刀石头布 【费用流】
- POJ.2142 The Balance (拓展欧几里得)
- LibreOJ #6221. 幂数 !(数论+dfs+剪枝)
- 使用自己的数据集训练和测试";caffenet";
- 【题解】Radio stations Codeforces 762E CDQ分治
- ssm项目,web容器无法初始化项目
- 第一章 深入web请求过程
- 实体框架(Entity Framework)快速入门--实例篇
- 理解JavaScript的prototype和__proto__