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的作用的。
Java单线程多实例和多线程多实例的更多相关文章
- java多线程编程实例
[转]这篇文章主要介绍了java多线程编程实例,分享了几则多线程的实例代码,具有一定参考价值,加深多线程编程的理解还是很有帮助的,需要的朋友可以参考下. 1.三个售票窗口同时出售20张票程序分析: ...
- (转)java线程安全问题之静态变量、实例变量、局部变量
java多线程编程中,存在很多线程安全问题,至于什么是线程安全呢,给出一个通俗易懂的概念还是蛮难的,如同<java并发编程实践>中所说: 写道 给线程安全下定义比较困难.存在很多种定义,如 ...
- java线程安全问题之静态变量、实例变量、局部变量
java多线程编程中,存在很多线程安全问题,至于什么是线程安全呢,给出一个通俗易懂的概念还是蛮难的,如同<java并发编程实践>中所说: 写道 给线程安全下定义比较困难.存在很多种定义,如 ...
- (转) C#多线程赛跑实例
专于:http://blog.csdn.net/lidatgb/article/details/8363035 结合上篇<多线程的基础>,这次我们写一个多线程的赛跑实例,内容很简单:超人和 ...
- JAVA单线程以及java多线程的实现方式
1.java单线程的实现 public class SingletonThread { @SuppressWarnings("static-access") public stat ...
- vc 基于对话框多线程编程实例——线程之间的通信
vc基于对话框多线程编程实例——线程之间的通信 实例:
- C#多线程编程实例 螺纹与窗口交互
C#多线程编程实例 螺纹与窗口交互 代码: public partial class Form1 : Form { //声明线程数组 Thread[] workThreads = new Thread ...
- c# 多线程 创建对象实例
本次的标题是我在写单例模式的博客时遇到的问题,所以今天专门写了的demo让自己记住怎么简单的使用多线程. 一直纠结的是怎么在for循环中多次实例化对象,好复现单例模式在没有加锁的情况下出现多个实例对象 ...
- linux下C语言多线程编程实例
用一个实例.来学习linux下C语言多线程编程实例. 代码目的:通过创建两个线程来实现对一个数的递加.代码: //包含的头文件 #include <pthread.h> #include ...
随机推荐
- 51NOD 1773:A国的贸易——题解
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1773 参考1:FWT讲解 https://www.cnblogs.com ...
- 差点AFO
差点就AFO了,小伙伴们一定注意护眼啊. 眼睛总算是活过来了. 还有一个月联赛,加油
- 【图论-最短路】【P3393】逃离僵尸岛
传送门 Description 小a住的国家被僵尸侵略了!小a打算逃离到该国唯一的国际空港逃出这个国家. 该国有N个城市,城市之间有道路相连.一共有M条双向道路.保证没有自环和重边. K个城市已经被僵 ...
- 简述JavaScript的类与对象
JavaScript语言是动态类型的语言,基于对象并由事件驱动.用面向对象的思想来看,它也有类的概念.JavaScript 没有class关键字,就是用function来实现. 1. 实现方式及变量/ ...
- PowerDesigner 技巧【1】
Name与Code同步的问题: PowerDesigner中,修改了某个字段的name,其code也跟着修改,这个问题很讨厌,因为一般来说,name是中文的,code是字段名. 解决方法如下: 1.选 ...
- UIScrollView控件及其三个常用属性:contentSize、contentInset和contentOffset
如果您对UIScrollView控件感到难以理解,下面是本人自己对UIScrollView控件的理解方式,按照我的思路,理解UIScrollView控件非常容易! 我对UIScrollView的构成理 ...
- k好数 数位dp
问题描述 如果一个自然数N的K进制表示中任意的相邻的两位都不是相邻的数字,那么我们就说这个数是K好数.求L位K进制数中K好数的数目.例如K = 4,L = 2的时候,所有K好数为11.13.20.22 ...
- bzoj1178 [Apio2009]CONVENTION会议中心 区间dp+贪心
[Apio2009]CONVENTION会议中心 Time Limit: 15 Sec Memory Limit: 162 MBSubmit: 1130 Solved: 444[Submit][S ...
- 「模板」 FHQ_Treap
「模板」 FHQ_Treap 我也是偶然发现我还没发过FHQ_Treap的板子. 那就发一波吧. 这个速度实在不算快,但是不用旋转,并且好写. 更重要的是,Splay 可以做的事情它都可以做!比如区间 ...
- Ubuntu12.04 安装nginx和mongo过程
1.安装php和php-cgi apt-get install php5 php5-cgi 2.安装 nginx apt-get install nginx 3.安装 MongoDB apt-get ...