精华内容
下载资源
问答
  • JAVA多线程共享变量

    2018-01-05 16:57:36
    方法1:多线程卖票 public class MutiThreadShareDataTest { public static void main(String[] args) { JobThread jobThread = new JobThread(); new Thread(jobThread).start(); new Th...

    方法1:多线程卖票

    public class MutiThreadShareDataTest {
        public static void main(String[] args) {
            JobThread jobThread = new JobThread();
            new Thread(jobThread).start();
            new Thread(jobThread).start();
        }
    
    }
    class JobThread implements Runnable{
        private int i = 100;
        @Override
        public void run() {
            while (i > 0){
                i--;
                System.out.println(Thread.currentThread().getName() + "剩下:" + i);
            }
            System.out.println("end");
        }
    }
    

     

    展开全文
  • Java多线程共享变量控制

    千次阅读 2017-09-07 15:39:48
    如果一个变量同时在线程的工作内存中存在副本,那么这个变量就叫共享变量   2. JMM(java内存模型) 线程同时对主内存的一个共享变量进行读取和修改时,首先会读取这个变量到自己的工作内存中成为一个副本,...
    1. 可见性

    如果一个线程对共享变量值的修改,能够及时的被其他线程看到,叫做共享变量的可见性。如果一个变量同时在多个线程的工作内存中存在副本,那么这个变量就叫共享变量

    1. JMM(java内存模型)

    多个线程同时对主内存的一个共享变量进行读取和修改时,首先会读取这个变量到自己的工作内存中成为一个副本,对这个副本进行改动之后,再更新回主内存中变量所在的地方。

    (由于CPU时间片是以线程为最小单位,所以这里的工作内存实际上就是指的物理缓存,CPU运算时获取数据的地方;而主内存也就是指的是内存,也就是原始的共享变量存放的位置)

    两条规定:

    a.线程对共享变量的所有操作必须在工作内存中进行,不能直接操作主内存

    b.不同线程间不能访问彼此的工作内存中的变量,线程间变量值的传递都必须经过主内存

    如果一个线程1对共享变量x的修改对线程2可见的话,需要经过下列步骤:

    a.线程1将更改x后的值更新到主内存

    b.主内存将更新后的x的值更新到线程2的工作内存中x的副本

    所以,要实现共享变量的可见性必须保证下列两点:

    a.线程对工作内存中副本的更改能够及时的更新到主内存上

    b.其他线程能够及时的将主内存上共享变量的更新刷新到自己工作内存的该变量的副本上

    Java中可以通过synchronized、volatile、java concurrent类来实现共享变量的可见性

    1. synchronized实现可见性

    synchronized 实际上是对访问修改共享变量的代码块进行加互斥锁,多个线程对synchronized代码块的访问时,某一时刻仅仅有一个线程在访问和修改代码块中的内 容(加锁),其他所有的线程等待该线程离开代码块时(释放锁)才有机会进入synchronized代码块。

    所以某一个线程进入synchronized代码块前后,执行过程入如下:

    a.线程获得互斥锁

    b.清空工作内存

    c.从主内存拷贝共享变量最新的值到工作内存成为副本

    d.执行代码

    e.将修改后的副本的值刷新回主内存中

    f.线程释放锁

    随后,其他代码在进入synchronized代码块的时候,所读取到的工作内存上共享变量的值都是上一个线程修改后的最新值。

    多个线程之间执行共同的代码块(访问修改共享变量),由于线程交叉执行,最终共享变量的最后值可能有多种结果:

    public class SynchronizedTest {
    
        private boolean ready = false;
        private int result = 0;
        private int number = 1;
    
        public void write(){
            ready = true;
            number = 2;
        }
    
        public void read(){if(ready){
                result = number * 3;
            }
    
            System.out.println("result is " + result);
        }
    
        private class TestThread extends Thread{
            private boolean flag;
            public TestThread(boolean flag){
                this.flag = flag;
            }
            @Override
            public void run() {
                // TODO Auto-generated method stub
                if(flag){
                    write();
                }else{
                    read();
                }
            }
        }
    
        public static void main(String[] args){
            SynchronizedTest test = new SynchronizedTest();
            test.new TestThread(true).start();
            test.new TestThread(false).start();
        }
    }

    如上代码,由于两个线程交叉执行,最后result的结果可能是0或者6或者3

    共享变量不可见主要有下列原因:

    a.线程的交叉执行

    b.重排序

    c.共享变量未能及时更新

    通过使用synchronized可以保证原子性(synchronized代码块内容要么不执行,要执行就保证全部执行完毕)和可见性,修改后的代码为在write和read方法上加synchronized关键字

    1. volatile实现可见性(jdk 1.5后)

    volatile如何实现可见性?

    volatile变量每次被线程访问时,都强迫线程从主内存中重读该变量的最新值,而当该变量发生修改变化时,也会强迫线程将最新的值刷新回主内存中。这样一来,不同的线程都能及时的看到该变量的最新值。

    但是volatile不能保证变量更改的原子性:

    比 如number++,这个操作实际上是三个操作的集合(读取number,number加1,将新的值写回number),volatile只能保证每一 步的操作对所有线程是可见的,但是假如两个线程都需要执行number++,那么这一共6个操作集合,之间是可能会交叉执行的,那么最后导致number 的结果可能会不是所期望的。

    所以对于number++这种非原子性操作,推荐用synchronized:

    synchronizedthis){
         number++;   
    }

    如下代码:最后的number的结果不一定是500,有可能是比500小,因为number++不是一个原子性的操作,用volatile不能保证可见性

    public class VolatileTest {
    
        public static int number = 0;
    
        public void increase(){
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            number++;
        }
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            final VolatileTest test = new VolatileTest();
            for(int i = 0 ; i < 500 ; i++){
                new Thread(new Runnable() {
    
                    @Override
                    public void run() {
                        test.increase();
    
                    }
                }).start();
            }
    
            //若当期依然有子线程没有执行完毕
            while(Thread.activeCount() > 1){
                Thread.yield();//使得当前线程(主线程)让出CPU时间片
            }
    
            System.out.println("number is " + number);
        }
    
    }

    对于自增之类的非原子性操作,只能通过如下方式保证可见性:

    a. synchronized

    b. ReentrantLock

    c. AtomicInteger

    synchronized修改如下:

    public void increase(){
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            synchronized(this){
                number++;
            }
    
        }

    ReentrantLock修改方式如下:

    public class VolatileTest {
    
        public static int number = 0;
        public Lock lock =  new ReentrantLock();
    
        public void increase(){
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
            lock.lock();
    
            try{
                number++;//这块的代码实际项目中可能会出现异常,所以要捕获
            }finally{
                lock.unlock();//用try finally块保证Unlock一定要执行
            }
    
    
        }
    
    。。。
    }

    AtomicInteger,一个提供原子操作的Integer的类。在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则通过一种线程安全的加减操作接口。

    修改如下:

    package com.mooc.test;
    
    import java.util.concurrent.atomic.AtomicInteger;
    
    public class VolatileTest {
    
        public static AtomicInteger number = new AtomicInteger(0);
    
        public void increase(){
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    
            number.getAndIncrement();//获得当前值并且加1
        }
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            final VolatileTest test = new VolatileTest();
            for(int i = 0 ; i < 500 ; i++){
                new Thread(new Runnable() {
    
                    @Override
                    public void run() {
                        test.increase();
    
                    }
                }).start();
            }
    
            //若当期依然有子线程没有执行完毕
            while(Thread.activeCount() > 1){
                Thread.yield();//使得当前线程(主线程)让出CPU时间片
            }
    
            System.out.println("number is " + number.get());
        }
    
    }
    1. volatile适用情况

    a.对变量的写入操作不依赖当前值

    比如自增自减、number = number + 5等(不满足)

    b.当前volatile变量不依赖于别的volatile变量

    比如 volatile_var > volatile_var2这个不等式(不满足)

    1. synchronized和volatile比较

    a. volatile不需要同步操作,所以效率更高,不会阻塞线程,但是适用情况比较窄

    b. volatile读变量相当于加锁(即进入synchronized代码块),而写变量相当于解锁(退出synchronized代码块)

    c. synchronized既能保证共享变量可见性,也可以保证锁内操作的原子性;volatile只能保证可见性

    展开全文
  • Main.java ...按照书上说的 不是共享变量多线程中是单独的副本吗 ser已经传入到ThreadA中 我在主线程中改变了状态值会影响到线程中的副本吗? 这段代码执行后 确实把循环停住了 求大神们帮忙看看
  •  500个线程同时操纵变量number,执行number++操作,结果并不一定等于500。  无论是否使用volatile 修饰number,结果都一样。 public class VolatileTest { public static volatile int number = 0; public ...

    一、异常情况

       500个线程同时操纵变量number,执行number++操作,结果并不一定等于500。

       无论是否使用volatile 修饰number,结果都一样。

    public class VolatileTest {
        public static volatile int number = 0;
        public void increase(){
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            number++;
        }
        
        public static void main(String[] args) {
            final VolatileTest test = new VolatileTest();
            for(int i = 0 ; i < 500 ; i++){
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        test.increase();
                    }
                }).start();
            }
            //若当期依然有子线程没有执行完毕
            while(Thread.activeCount() > 2){
                //使得当前线程(主线程)让出CPU时间片
                Thread.yield();
            }
            System.out.println("number is " + number);
        }
    }

     

    二、改进方式

       2.1使用synchronized

     

     public void increase(){
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized(this){
                number++;
            }
        }

     

       2.2使用ReentrantLock

     

    import java.util.concurrent.locks.Lock;
    import java.util.concurrent.locks.ReentrantLock;
    
    public class VolatileTest {
        public static  int number = 0;
        public Lock lock =  new ReentrantLock();
    
        public void increase(){
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lock.lock();
            try{
                number++;
            }finally{
                lock.unlock();
            }
        }
    
        public static void main(String[] args) {
            final VolatileTest test = new VolatileTest();
            for(int i = 0 ; i < 500 ; i++){
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        test.increase();
                    }
                }).start();
            }
            //若当期依然有子线程没有执行完毕
            while(Thread.activeCount() > 2){
                //使得当前线程(主线程)让出CPU时间片
                Thread.yield();
            }
            System.out.println("number is " + number);
        }
    }
    

       2.3 AtomicInteger

        AtomicInteger,一个提供原子操作的Integer的类。在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而AtomicInteger则通过一种线程安全的加减操作接口

     

    import java.util.concurrent.atomic.AtomicInteger;
    
    public class VolatileTest {
        public static AtomicInteger number = new AtomicInteger(0);
    
        public void increase(){
            try {
                Thread.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            number.getAndIncrement();//获得当前值并且加1
        }
    
        public static void main(String[] args) {
            final VolatileTest test = new VolatileTest();
            for(int i = 0 ; i < 500 ; i++){
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        test.increase();
                    }
                }).start();
            }
            //若当期依然有子线程没有执行完毕
            while(Thread.activeCount() > 2){
                //使得当前线程(主线程)让出CPU时间片
                Thread.yield();
            }
            System.out.println("number is " + number);
        }
    }
    

     

    三、volatile适用情况

        对变量的写入操作不依赖当前值 
             比如自增自减、number = number + 5等(不满足)
        当前volatile变量不依赖于别的volatile变量
            比如 volatile_var > volatile_var2这个不等式(不满足)

     四、synchronized和volatile比较

        volatile不需要同步操作,所以效率更高,不会阻塞线程,但是适用情况比较窄 

        volatile读变量相当于加锁(即进入synchronized代码块),而写变量相当于解锁(退出synchronized代码块)
        synchronized既能保证共享变量可见性,也可以保证锁内操作的原子性;volatile只能保证可见性
    展开全文
  • 一个简单记录java多线程变量共享问题,分析多线程内部运行
  • java多线程共享变量

    2018-12-25 15:35:01
    目的:简述java多线程共享变量 共享变量:多个线程都会使用到的同一变量。 Q : 为什么共享变量会造成数据的错误呢??? A : 多个线程在操作共享变量的时候,不是直接在主内存中去操作的。而是都取一个...

    目的:简述java多线程的共享变量

     

    共享变量:多个线程都会使用到的同一变量。

     

    Q : 为什么共享变量会造成数据的错误呢???

     

        A : 多个线程在操作共享变量的时候,不是直接在主内存中去操作的。而是都取一个共享变量的副本在工作内存去进行相关作。

     

    下面举例说明:有两个线程同时操作一个共享变量(默认值是0),线程一,让共享变量加2,线程二,让共享变量减3。那么结果应该是-1.

     

    但实际可能是:线程一,拿到了主内存的数据(0),加2,还没有同步到主内存中去,线程二已经取出了主内存的数据(0),减3,这时候线程一,同步到主内存中去。数据变成2,然后线程二开始同步数据,数据变成-3。

     

     

    解决办法:volatile 和 synchronized 关键字。

    展开全文
  • JAVA多线程——共享变量

    千次阅读 2018-11-12 10:53:09
    【转载】Java多线程编程:变量共享分析(Thread) 原博客网址:https://www.cnblogs.com/xudong-bupt/archive/2013/05/22/3087864.html 今天看到java的多线程,感到十分激动,之前就在python中使用过多...
  • Java线程共享变量

    千次阅读 2019-12-04 15:16:46
    这篇文章描述两种线程共享实例变量的通用模型,一个Java线程是Thread类的实例,一个thread必须从一个thread base创建。一个thread包含一个thread base和隐藏的控制结构,隐藏的控制结构允许thread可以与其他线程并行...
  • 主要介绍了Java多线程编程之ThreadLocal线程范围内的共享变量,本文讲解了ThreadLocal的作用和目的、ThreadLocal的应用场景、ThreadLocal的使用实例等,需要的朋友可以参考下
  • 【自己的总结】 package dc.stock; import dc.stock.policies.StockP1_1_... * 之所以单独列出来,是为了多线程的使用; */ public class MainRunStockPolicy { public static void main(String[] args...
  • java线程共享变量与静态变量

    千次阅读 2013-04-05 11:22:22
    以下三种情况说明java中全局变量与静态变量线程间的关系 情况一: /** * 两个线程对【两】个对象操作,这两个对象的类中的【静态变量线程共享】 * * @author thinktown * */ public class Test1 ...
  • java多线程全局变量共享问题

    万次阅读 2018-07-17 20:14:09
    先看下面问题:线程访问全局变量x,然后将x与i累加,启动10个线程,想让每个线程的输出结果都是一样的55,但是实际不是的。 package ThreadTest; public class Counter { private int x =0; // 计数方法...
  • 多线程共享变量方式

    千次阅读 2015-08-25 17:15:06
    多线程共享变量的三种方式
  • 这包括了多线程共享变量的可见性和原子性操作;(共享变量:如果一个变量在多个线程的工作内存(工作内存:每个线程都有自己的工作内存)中都存在副本,那么这个变量就是这几个线程的共享变量) 在java内存模型中,...
  • Java多线程共享全局变量问题

    千次阅读 2015-10-24 20:58:46
    现在安全问题,在我们做开发时只要涉及多线程都是属于必须考虑的问题,但多线程是个神奇的东西,东西太多,很难全部掌握,在这里我也是通过例子来见证他的奇迹 1.会出现问题的例子  计数的类: public class ...
  • java多线程共享变量访问控制实例

    千次阅读 2015-09-11 15:44:10
    最近打算去一家电商公司,对于高并发的数据访问控制有着严格的要求,近期打算把多线程的知识在好好补一下。 线程调度有五个状态; 开始,可运行,运行,阻塞,死亡。 启动线程有两种方法。继承Thread类或则实现...
  • JAVA多线程共享变量的可见性问题

    千次阅读 2019-05-22 17:13:47
    这篇文章总结哪些代码会使线程去主内存拉取变量。 二、volatile volatile修饰的变量,不论什么语句都会从主内存拉取变量。 该程序能顺利完成,不会死循环。因为“isStop ”用volatile修饰了 三、synchronized 调用...
  • 万字图解Java多线程

    万次阅读 多人点赞 2020-09-06 14:45:07
    java多线程我个人觉得是javaSe中最难的一部分,我以前也是感觉学会了,但是真正有多线程的需求却不知道怎么下手,实际上还是对多线程这块知识了解不深刻,不知道多线程api的应用场景,不知道多线程的运行流程等等,...
  • synchronized 实际上是对访问修改共享变量的代码块进行加互斥锁,线程对synchronized代码块的访问时,某一时刻仅仅有一个线程在访问和修改代码块中的内 容(加锁),其他所有的线程等待该线程离开代码块时(释放...
  • 什么是线程范围内共享变量?  线程范围内的共享变量是指对同一个变量,几个线程同时对它进行写和读操作,而同一个线程读到的数据就是它自己写进去的数据。也就是说每个线程只能访问他自己的,不能访问别的线程的。 ...
  • 本文全文以售票系统为例,简诉了java多线程共享数据的两种方式、线程同步。文章可能还有很多不足,请大家谅解,欢迎大佬提意见。 本文使用到的东西 java eclipse 2019-11 文章目录写在前面本文使用到的东西1....
  • JAVA多线程中访问变量问题

    千次阅读 2017-03-27 18:51:27
    变量(类里面static修饰的变量)保存在“方法区”实例变量(类里面的普通变量)保存在“堆”局部变量(方法里声明的变量)...事实上,在java中,多线程间进行通信的唯一途径就是通过类变量和实例变量。也就是说
  • Java并发:线程共享变量可见性原理

    千次阅读 2018-04-02 16:53:26
    (1)在共享内存的并发模型里,线程之间共享程序的公共状态,线程之间通过写-读内存中的公共状态来隐式进行通信,典型的共享内存通信方式就是通过共享对象进行通信。(2)在消息传递的并发模型里,线程之间没有公共...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 226,347
精华内容 90,538
关键字:

java多线程共享变量

java 订阅