java多线程操作同一个变量的问题,难道是多核cpu所致?

问题描述

java多线程操作同一个变量的问题,难道是多核cpu所致?

大家请看代码和输出结果,我百思不得其解,为什么 amount只加了一次,开始我以为是static所致,就算去掉也还是有几率出现这样的结果,难道是多核cpu真的把两个线程同时执行了?

package study;

public class MyRunnable implements Runnable {

    public static int  amount=0;
    @Override
    public void run() {
        // TODO 自动生成的方法存根
        amount++;
        String s=Thread.currentThread().getName();
        System.out.println(s+"  "+amount);
    }
}
package study;

public class MyFirstThread {

    public static void main(String[] args) {
        // TODO 自动生成的方法存根
         MyRunnable r1=new MyRunnable();
     Thread AThread=new Thread(r1);
     Thread BThread=new Thread(r1);
     AThread.start();
     BThread.start();

  for(;;)
  {
      if((!AThread.isAlive())&&(!BThread.isAlive()))
      {
        System.out.println("amount ="+r1.amount);
        break;
      }
  }

    }
}

解决方案

没有加同步锁的问题,两个线程是同时执行的,amount什么值都有可能,可能都是1,可能打印都是2,也可能打印2,1。所以需要对amount加同步锁

 public static Integer  amount=0;
    @Override
    public void run() {
        // TODO 自动生成的方法存根
        synchronized(amount){
            amount++;
            String s=Thread.currentThread().getName();
            System.out.println(s+"  "+amount);
        }
    }

解决方案二:

如果只有一个处理器,仍然可能出现线程同步的问题,和什么多cpu同时执行没有关系。

我再说清楚一些

这是因为amount++;不是原子化的操作,它是这样的
int x = amount;
x = x + 1;
amount = x;
(这里x代表寄存器,amount代表内存)
我们假设你只有1个cpu,也就是执行本身不是并发的,但是有两个线程

假设amount = 0
线程1
int x = amount;
此时x = 0, amount=0
切换到线程2
注意,x是寄存器,每个线程独立,而amount是共享的,只有一个,所以为了避免混淆,这里x写成x1表示另一个变量
int x1 = amount;
此时x1=0 amount=0
x1 = x1 + 1;
此时x1=1
再切换到线程1
x = x + 1;
amount = x;
此时x = 1
amount=1
再切换到线程2
amount = x1;
记住,x1=1
所以amount=1
结果是1而不是2
为什么这样?因为x存的数据是脏数据,amount被另一个线程更新了,但是x没有更新。
注意,以上代码不是并行执行的,同样有同步问题。

解决方案三:

晕,线程没有同步,无论单核多核都需要线程同步。这是起码的常识。

解决方案四:

无论单核多核都不是同步执行的,CPU在各个线程随机执行(优先级高的线程得到CPU执行的机会更多),你所看到的同步,其实是CPU在线程之间切换执行,只是速度太快,我们无法跟上。

解决方案五:

可以看看龙书的线程同步,讲的十分仔细。 《operating system concepts》

解决方案六:

对,单核时代,同一时刻,只有一个执行,现在多核时代了

时间: 2024-12-26 20:46:45

java多线程操作同一个变量的问题,难道是多核cpu所致?的相关文章

java读取操作系统环境变量

变量 java读取操作系统环境变量 /**文件名:SysProb.java描述: 取得当前系统变量的程序. java中的System.getProperty只是针对JVM来的,如果要取得系统环境变量,还要用到系统相关的函数作者: 慈勤强Email :cqq1978@Gmail.com**/ import java.util.*;import java.io.*; class SysProb{ //返回当前系统变量的函数,结果放在一个Properties里边,这里只针对win2k以上的,其它系统可

关于java多线程操作invokeAll空指针的问题

问题描述 关于java多线程操作invokeAll空指针的问题 求救各位大神: public static void threadTestAll(String dirName) { long start = System.currentTimeMillis(); ExecutorService pool = Executors.newFixedThreadPool(30); List<Callable<String>> tasks = new ArrayList<Callab

请教多线程操作同一个数据表时,怎么避免表死锁

问题描述 最近有一个数据采集的项目,要求可以多路并发,遇到多线程操作同一个数据表的问题,经常发生表死锁,求各位大侠帮忙,大约有20-40个进程实例化读取类,类中Receive方法接收数据并存储上代码publicclassclsTranslateObj{privatevoidReceive(){intlenReceive=0;byte[]receivedByte=newbyte[BUFFER_SIZE];//接收返回字节数组_rtnStr=string.Empty;while(_flgConnec

java多线程读写同一个文件

问题描述 同一个文件可以同时被一个线程读另一个线程写吗? 解决方案 如果有一个线程正在读文件,这时又有另个一个线程想来写这个文件 会报错吗?答案是不会.请运行以下的代码 就知道了package org.sse.test;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOExc

Java多线程编程:变量共享分析(Thread)

在编写多线程程序时,最重要的就是搞清楚哪些变量是共享的,哪些变量是不共享的.也就是要分析清楚其中的原理呀. 因为最近要使用多线程就看了一些,对使用Thread类的子类创建线程的情况,总结如下: 1.方法体内部定义的局部变量不共享   这是因为方法内部定义的变量是在运行时动态生成的.每个线程都有一个自己的堆栈,用于保存运行时的数据. 最容易理解的就是递归调用时候,每次的入栈出栈操作.如下,每次调用时,变量aa都是在运行时堆栈上保存的,方法结束变量也就释放了. public int fib(int

java多线程和并发包入门示例_java

一.java多线程基本入门java多线程编程还是比较重要的,在实际业务开发中经常要遇到这个问题. java多线程,传统创建线程的方式有两种. 1.继承自Thread类,覆写run方法. 2.实现Runnable接口,实现run方法. 启动线程的方法都是调用start方法,真正执行调用的是run方法.参考代码如下: 复制代码 代码如下: package com.jack.thread; /** * 线程简单演示例子程序 *  * @author pinefantasy * @since 2013-

关于多个线程操作同一变量遇到问题,求指教

问题描述 我想实现多个线程对同一个变量进行累加,当某个线程发现这个变量超过指定值比如300,就在这个线程内部结束所有的线程运行,我写的代码如下,为什么运行的时候还是有些线程没有被结束掉呢?privateintflag=0;Thread[]threads=newThread[20];privateobjectLockThis=newSystem.Object();privatevoidbutton4_Click(objectsender,EventArgse){for(inti=0;i<threa

Java多线程之线程间协作 notify与wait的使用

(转载请注明出处:http://blog.csdn.net/buptgshengod) 1.背景        Java多线程操作运用很广,特别是在android程序方面.线程异步协作是多线程操作的难点也是关键,也是找工作面试经常考到的地方.下面分享一下我的使用心得. 介绍几个关键字: synchronized:线程锁,使得系统只执行当前线程. notifyAll():唤醒其它被锁住的线程 wait():挂起线程 ExecutorService exec=Executors.newCachedT

深入探讨Java多线程中的volatile变量_java

volatile 变量提供了线程的可见性,并不能保证线程安全性和原子性. 什么是线程的可见性: 锁提供了两种主要特性:互斥(mutual exclusion) 和可见性(visibility).互斥即一次只允许一个线程持有某个特定的锁,因此可使用该特性实现对共享数据的协调访问协议,这样,一次就只有一个线程能够使用该共享数据.可见性要更加复杂一些,它必须确保释放锁之前对共享数据做出的更改对于随后获得该锁的另一个线程是可见的 -- 如果没有同步机制提供的这种可见性保证,线程看到的共享变量可能是修改前