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 ...
随机推荐
- fhq_treap 学习笔记
前言:昨天写NOIp2017队列,写+调辗转了3h+,不知道怎么的,就点进了一个神仙的链接,便在今日学习了神仙的fhq_treap. 简介:fhq_treap功能强大,支持splay支持的所有操作,代 ...
- application.properties 改成 application.yml
application.properties 改成 application.yml
- JNA的用法
JNA(Java Native Access):建立在JNI之上的Java开源框架,SUN主导开发,用来调用C.C++代码,尤其是底层库文件(windows中叫dll文件,linux下是so[shar ...
- django error: DisallowedHost: Invalid HTTP_HOST header: ''. You may need to add u'' to ALLOWED_HOST
测试环境: [root@nanx-lli ~]# lsb_release -aLSB Version: :core-4.1-amd64:core-4.1-noarchDistributor ID: C ...
- STL之二:vector容器用法详解
转载于:http://blog.csdn.net/longshengguoji/article/details/8507394 vector类称作向量类,它实现了动态数组,用于元素数量变化的对象数组. ...
- Leetcode 001. 两数之和(扩展)
1.题目要求 给定一个整数数组和一个目标值,找出数组中和为目标值的两个数. 你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用. 示例: 2.解法一:暴力法(for*for,O(n*n)) ...
- RabbitMQ 作用
1.RabbitMQ 作用 同步变异步 解耦 削峰 2.
- c# MD5盐值加密
using System; using System.Collections.Generic; using System.Linq; using System.Security.Cryptograph ...
- css 常用苹方字体
// 苹方-简 常规体 font-family: PingFangSC-Regular, sans-serif; // 苹方-简 极细体 font-family: PingFangSC-Ultrali ...
- js处理时间的那些事
我们在实际需求中一般需要对时间进行相应的出来,比如:对时间串的拆分显示,两个时间差的求值显示等. 时间拆分: 一般对于这种处理我们使用正则表示式: 正则表达式拆分时间: var date = data ...