精华内容
下载资源
问答
  • 多线程访问静态方法中的静态变量

    千次阅读 2017-09-04 00:39:59
    背景:近期,项目中遇到一个场景,多线程访问一个数组,从下标0开始一直到最大长度,然后再从下标0开始,如此循环往复(线程0访问数组下标0,线程1访问数组下标1......)。下标的数值由一个静态变量共享。当时是这么...

    背景:近期,项目中遇到一个场景,多线程访问一个数组,从下标0开始一直到最大长度,然后再从下标0开始,如此循环往复(线程0访问数组下标0,线程1访问数组下标1......)。下标的数值由一个静态变量共享。当时是这么写的,没有考虑多线程的问题:

    public class AppUtils {
    
    	private final static int LIMIT = 10;
    	private final static int ORIGIN = 0;
    	
    
    	// 共享变量
    	public static int counter = 0;
    	// 错误示范
    	public  static int getKeyNumByNext() {
                    // 条件重置
    		if (counter == LIMIT) {
    			counter = ORIGIN;
    		}
    		System.out.println(Thread.currentThread().getName() +":"+counter);
    		counter += 1;
    		return counter;
    	}
    
    	private CountDownLatch cdl;
    
    	@Test
    	public void test() {
    		// 模拟并发数
    		int concurrentNum = 100;
    
    		cdl = new CountDownLatch(concurrentNum);
    
    		for (int i = 0; i < concurrentNum; i++) {
    			new Thread(new UserRequest()).start();
    			cdl.countDown();
    		}
    
    		try {
    			Thread.currentThread().sleep(5000);
    			System.out.println("======="+counter);
    			//System.out.println("======="+atomCounter.get());
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    	}
    
    	class UserRequest implements Runnable {
    
    		@Override
    		public void run() {
    			try {
    				cdl.await();
    				// 非安全
    				getKeyNumByNext();
    				// 安全
    				//getAtomKeyNumByNext();
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    
    		}
    	}
    }

    显然,静态变量counter可能在同一时间被多个线程修改,导致条件重置失败(数组下标最大为9,已经有线程到了10+)。


    后来,把getKeyNumByNext方法改成了synchronized,保证了变量的线程安全。但是这样肯定会影响性能。于是想起了jdk提供的一种原子操作类型AtomicInteger:

    // 原子操作
    	public static AtomicInteger atomCounter = new AtomicInteger();
    
    	public static int getAtomKeyNumByNext() {
    		atomCounter.incrementAndGet();
    		atomCounter.compareAndSet(LIMIT,ORIGIN);
    		System.out.println(Thread.currentThread().getName() +":"+atomCounter.get());
    		return atomCounter.get();
    	}

    不仅保证了性能,也保证了计数变量atomCounter的线程安全。这里运用到了一个并发处理的技术:CAS(Compare and swap)。简单的说,比较和替换是使用一个期望值和一个变量的当前值进行比较,如果当前变量的值与我们期望的值相等,就使用一个新值替换当前变量的值;如果不等,就重新再取一次:



    后台同时指出,还有更简单的方法,把错误示范中的条件重置 的 “==” 改为 “>=”  偷笑


    相互探讨,如有缪误,还望指正。

    展开全文
  • 多线程静态变量及C# Volatile关键字

    千次阅读 2013-04-27 13:58:58
    曾经以为,多线程可以访问静态变量,来实现多线程之间数据的共享。 事实上,虽然多线程可以访问静态变量,但是,会有延迟,可能访问的并不是最新的值。 要想在多个线程之间共享数据,并能及时访问到最新值,需要用...

    曾经以为,多线程可以访问静态变量,来实现多线程之间数据的共享。

    事实上,虽然多线程可以访问静态变量,但是,会有延迟,可能访问的并不是最新的值。

    要想在多个线程之间共享数据,并能及时访问到最新值,需要用Violate关键字。

    以下是关于Volatile关键字的说明

    volatile 关键字指示一个字段可以由多个同时执行的线程修改。声明为 volatile 的字段不受编译器优化(假定由单个线程访问)的限制。这样可以确保该字段在任何时间呈现的都是最新的值。

    volatile 修饰符通常用于由多个线程访问但不使用 lock 语句对访问进行序列化的字段。



    展开全文
  • 多线程静态变量,普通变量(实例变量),局部变量,静态方法,普通方法 的线程安全问题 类型 是否安全 存储位置 解释 静态变量 线程不安全 方法区 静态变量为类所持有,为所有对象共享,全局只有一份,...


    多线程中 静态变量,普通变量(实例变量),局部变量,静态方法,普通方法 的线程安全问题

    类型 是否安全 存储位置 解释
    静态变量 线程不安全 方法区 静态变量为类所持有,为所有对象共享,全局只有一份,一旦静态变量被修改,其他对象均对修改可见,所以线程不安全
    普通变量(实例变量) 单例模式下不安全
    非单例模式下安全
    普通变量为这个对象实例私有,在虚拟机的堆中分配,单例模式下,所有的操作都是针对这一个对象的属性,就会像静态变量那样,一旦被某个线程修改后,对其他的线程都可见,所以非线程安全。如果每个线程执行都是一个新的对象,每个对象间的属性就不会产生影响,所以是线程安全的。
    局部变量 线程安全 每个线程执行的时候,会把局部变量保存在各自的栈帧的工作内存中,线程之间不共享不可见,所以不存在线程安全问题
    静态方法 引用静态变量不安全
    没有引用静态变量安全
    方法区 如果引用了静态变量,情形就如果静态变量的结果(只能存在引用静态变量,静态方法和属性可以被非静态引用,但是静态不能引用非静态,因为静态方法在类加载的时候就初始化了,除了final类型),不引用就是一个普通的方法,只不过加上静态修饰后,在整个JVM中只会保存一份。
    普通方法 是否引用了变量,以及是否单例运行 单例情况下,如果没有引用内部的变量,线程安全的,非单例的情况下,引不引入变量都是安全的。

    测试静态变量

    所有的线程操作一个变量,线程之间不安全

    public class StaticTest implements Runnable {
    
        // 此处定义一个静态变量
        private static int i;
    
        /**
         * 在线程运行的时候,如果正常的情况下应该输出,2,10
         * 如果证明线程不安全,即其他线程修改了别的线程正常运行的值
         * 会出现A线程把i修改为5,即将执行i*2=10的时候,其他线程B把i修改为2,使结果输出为4
         * A线程把i赋值为2,即将执行输出i=2的时候,线程B把i修改为5,使结果输出为5
         * 无论输出4,5都是线程不安全的体现
         */
        @Override
        public void run() {
            i=2;
            System.out.println("["+Thread.currentThread().getName()+"] 当前静态变量i="+i);
            i=5;
            System.out.println("["+Thread.currentThread().getName()+"] 当前静态变量i="+i*2);
        }
    
        public static void main(String[] args) {
            StaticTest test = new StaticTest();
            for(int i=0;i<1000;i++){
                new Thread(test,"线程"+i).start();
            }
            /**
             * [线程245] 当前静态变量i=2
             * [线程245] 当前静态变量i=4
             * [线程246] 当前静态变量i=2
             * [线程172] 当前静态变量i=10
             * [线程177] 当前静态变量i=5
             * [线程177] 当前静态变量i=10
             * [线程179] 当前静态变量i=5
             * [线程179] 当前静态变量i=10
             * [线程171] 当前静态变量i=2
             * [线程171] 当前静态变量i=10
             * [线程180] 当前静态变量i=5
             */
        }
    }
    

    测试普通变量 单例

    所有的线程一同操作,一个对象中的一个属性,会产生线程争用的情况,所以线程不安全

    public class NormalTest implements Runnable {
    
        // 此处定义一个变量
        private int i;
    
        /**
         * 在线程运行的时候,如果正常的情况下应该输出,2,10
         * 如果证明线程不安全,即其他线程修改了别的线程正常运行的值
         * 会出现A线程把i修改为5,即将执行i*2=10的时候,其他线程B把i修改为2,使结果输出为4
         * A线程把i赋值为2,即将执行输出i=2的时候,线程B把i修改为5,使结果输出为5
         * 无论输出4,5都是线程不安全的体现
         */
        @Override
        public void run() {
            i=2;
            System.out.println("["+Thread.currentThread().getName()+"] 当前变量i="+i);
            i=5;
            System.out.println("["+Thread.currentThread().getName()+"] 当前变量i="+i*2);
        }
    
        public static void main(String[] args) {
            NormalTest test = new NormalTest();
            for(int i=0;i<1000;i++){
                new Thread(test,"线程"+i).start();
            }
            /**
             * [线程190] 当前变量i=10
             * [线程187] 当前变量i=5
             * [线程187] 当前变量i=10
             * [线程944] 当前变量i=2
             * [线程945] 当前变量i=4
             * [线程949] 当前变量i=2
             */
        }
    }
    

    测试普通变量 非单例

    每一个对象里面的属性都是线程单独拥有,不会存在互相争用的情况,线程安全

    public class NormalTest implements Runnable {
    
        // 此处定义一个变量
        private int i;
    
        /**
         * 在线程运行的时候,如果正常的情况下应该输出,2,10
         */
        @Override
        public void run() {
            i=2;
            System.out.println("["+Thread.currentThread().getName()+"] 当前变量i="+i);
            i=5;
            System.out.println("["+Thread.currentThread().getName()+"] 当前变量i="+i*2);
        }
    
        public static void main(String[] args) {
            for(int i=0;i<1000;i++){
                new Thread(new NormalTest(),"线程"+i).start();
            }
            /**
             * [线程190] 当前变量i=10
             * [线程187] 当前变量i=10
             * [线程944] 当前变量i=2
             * [线程949] 当前变量i=2
             */
        }
    }
    

    测试静态方法

    静态方法只能引用静态变量和静态方法,引用后等于静态变量的处理

    public class NormalTest implements Runnable {
    
        // 此处定义一个静态变量
        private static int i;
    
        /**
         * 在线程运行的时候,如果正常的情况下应该输出,2,10
         * 如果证明线程不安全,即其他线程修改了别的线程正常运行的值
         * 会出现A线程把i修改为5,即将执行i*2=10的时候,其他线程B把i修改为2,使结果输出为4
         * A线程把i赋值为2,即将执行输出i=2的时候,线程B把i修改为5,使结果输出为5
         * 无论输出4,5都是线程不安全的体现
         */
        @Override
        public void run() {
            add();
        }
    
        public static void add() {
            i=2;
            System.out.println("["+Thread.currentThread().getName()+"] 当前变量i="+i);
            i=5;
            System.out.println("["+Thread.currentThread().getName()+"] 当前变量i="+i*2);
        }
    
        public static void main(String[] args) {
            NormalTest t = new NormalTest();
            for(int i=0;i<1000;i++){
                new Thread(t,"线程"+i).start();
            }
            /**
             * [线程161] 当前变量i=2
             * [线程161] 当前变量i=4
             * [线程251] 当前变量i=2
             * [线程794] 当前变量i=10
             * [线程818] 当前变量i=5
             * [线程818] 当前变量i=10
             */
        }
    }
    

    测试普通方法

    普通方法引用变量后,单例情况下线程不安全,多例下线程安全
    没有引用变量,线程安全

    展开全文
  • JAVA 多线程编程 安全结论: 静态变量:线程非安全。...实例变量为对象实例私有,在虚拟机的堆中分配,若在系统中只存在一个此对象的实例,在多线程环境下,“犹如”静态变量那样,被某个线程修改后,其

    JAVA 多线程编程 安全结论:

    静态变量:线程非安全。

    静态变量即类变量,位于方法区,为所有对象共享,共享一份内存,一旦静态变量被修改,其他对象均对修改可见,故线程非安全。

    实例变量:单例模式(只有一个对象实例存在)线程非安全,非单例线程安全。

    实例变量为对象实例私有,在虚拟机的堆中分配,若在系统中只存在一个此对象的实例,在多线程环境下,“犹如”静态变量那样,被某个线程修改后,其他线程对修改均可见,故线程非安全;如果每个线程执行都是在不同的对象中,那对象与对象之间的实例变量的修改将互不影响,故线程安全。

    局部变量:线程安全。

    每个线程执行时将会把局部变量放在各自栈帧的工作内存中,线程间不共享,故不存在线程安全问题。



    使用ThreadLocal 解决多线程安全访问静态变量的问题:

    Android中 Handler 获取消息队列时,不管是主线程还是工作线程都是调用: Looper.myLooper(); 方法,然而 myLooper 方法中确用到了 静态变量sThreadLocal;

    按照一般的理解,Java 多线程访问静态变量是线程非安全的,主线程 和工作线程 得到的Looper是同一个looper对象才对,进而得到的是同一个消息队列:mQueue;如果真是这样的话,所有消息都在一个队列里面,岂不是出问题了?!

    Android 用ThreadLocal 轻而易举就解决了问题:

    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();



    关于ThreadLocal :

    主题:深入浅出ThreadLocal   http://www.iteye.com/topic/757478

    主题:正确理解ThreadLocal  http://www.iteye.com/topic/103804

    ThreadLocal并不是一个Thread  http://www.cnblogs.com/xubiao/p/5462170.html

    展开全文
  • 最近用到三层线程。 1个主线程,创建个子线程,处理主逻辑。 子线程,创建个子子线程,处理子逻辑。 子子线程,处理这种逻辑。...statc是静态变量,该变量在全局数据区分配内存。所以线程会出现混乱。
  • 局部静态变量多线程问题

    千次阅读 2014-06-26 20:46:23
    局部静态变量多线程问题
  • 类的成员分为两类,静态成员(static member)和实例成员(instance member)。静态成员属于类;实例成员则属于对象,即类的实例。 先看一个类:public class staticDemo { static int result; static int Addone...
  • c#多线程应用和静态变量

    千次阅读 2010-12-26 10:19:00
    在c#开发过程中,不可避免要用到多线程。当在子线程中访问主UI线程中的控件时,可以用委托,控件的invoke等。也可以设置全局静态变量CheckForIllegalCrossThreadCalls:CheckForIllegalCrossThreadCalls = false;//...
  • 多线程请求给静态变量加锁的

    千次阅读 2019-12-25 18:36:08
    今天在写一个当每次请求过来定义的一个静态变量累加的时候遇到很多坑,发现自己对多线程和锁的理解和使用一窍不通,对Java一些设计模式真的是一知半解!!心生惭愧,感谢部门大佬耐心的讲解和帮助!让我也明白写程序...
  • java线程共享变量与静态变量

    千次阅读 2013-04-05 11:22:22
    以下三种情况说明java中全局变量与静态变量线程间的关系 情况一: /** * 两个线程对【两】个对象操作,这两个对象的类中的【静态变量线程间共享】 * * @author thinktown * */ public class Test1 ...
  • 对于多线程中的全局静态变量,如果每个线程都会使用到而且要改变变量值里,要对变量操作进行锁定,否则会出现在不同线程获取的变量值不相同的情况。
  • 类的成员分为两类,静态成员(static member)和实例成员(instance member)。静态成员属于类;实例成员则属于对象,即类的实例。 先看一个类: public class staticDemo { static int result; static int Addone...
  • 静态变量多线程同步问题

    千次阅读 2018-08-31 14:46:15
    我们先来讨论一个问题,一个类的静态变量当类被次实例化的时候,静态变量是否会受影响?首先我们应该清楚的是静态变量是在类被JVM classloader的时候分配内存,并且是分配在永久区而非堆内存中。 当我们用对象锁...
  • C++当中常常需要一个全局唯一的对象... 既然全局变量是可能有害的,那么,我们我们把它隐藏一下,放到某个类当中去,作为类的静态数据成员。这看上去不错,我也这么认为。当我们只是简单的需要一个全局对象时,这很
  • 当字段被ThreadStatic特性修饰后,它的值在每个线程中都是不同的,即每个线程对static字段都会重新分配内存空间,就当然于一次new操作,这样一来,由于static字段所产生的问题也就没有了,这种static数据上下文是...
  • 1. 静态变量线程不安全 静态变量位于方法区,为所有对象共享,它们共享一份内存,一旦静态变量被修改,其他对象均对修改可见,故线程不安全。 public class Test1 implements Runnable { private static int ...
  • 很简单的逻辑,就是for循环开新的线程然后每个线程执行对static静态变量count的修改。 在inc()方法中,对count用for循环执行操作很重要。因为现在的电脑性能都应经很好(一般情况下资源都浪费了),所以如果简单...
  • JAVA多线程——共享变量

    千次阅读 2018-11-12 10:53:09
    【转载】Java多线程编程:变量共享分析(Thread) 原博客网址:https://www.cnblogs.com/xudong-bupt/archive/2013/05/22/3087864.html 今天看到java的多线程,感到十分激动,之前就在python中使用过多...
  • 创建线程时,线程函数如果要设置成类的成员函数,则必须是静态成员函数,在此函数种不能使用非静态成员变量,如果要使用非静态成员变量,则一种比较适合线程的方法是:建立线程的时候把this作为CreateThread的一个...
  • 多线程程序中,无论我们使用AfxBeginThread ,CreateThread,_beginthread构造线程函数,因为线程函数只能是全局函数或静态函数,下面拿静态函数来举例说明,静态函数中可以直接访问静态成员,但是访问类的非静态...
  • ``` package thread.worker; /** ... * Created by huli3 on 2017/8/16. ... public static void main(String[] args) throws InterruptedException { ... System.out.println(threadGroup.activeCount() + " sum " + ...
  • java类全局静态变量多线程中数据混乱问题 解决方法: 可以使用ThreadLocal实现线程内的数据共享,而在另外线程中运行时又共享另外一份数据。 用法:http://www.yayihouse.com/yayishuwu/chapter/1174
  • 如下所示,product1, product2,product3是三个不同的线程,但由于Producer类里面的成员变量count是静态变量,所以实际上count是三个线程的共享成员变量,对其进行操作时,最好加上锁访问机制。package java_thread_...
  • 静态变量:线程非安全。...实例变量为对象实例私有,在虚拟机的堆中分配,若在系统中只存在一个此对象的实例,在多线程环境下,“犹如”静态变量那样,被某个线程修改后,其他线程对修改均可见,故线
  • 使用两个线程调用同一静态方法(该静态方法不引用静态变量)、第一个线程被阻塞的时间大于第二个线程被阻塞的时间,若第一个线程与第二个线程的输出结果相同,则两个线程调用同一静态方法存在线程安全问题,若第一个...
  • 对于SpringMVC Controller单例和多例,下面举了个例子说明下. 第一次:类是多例,一个普通属性和一个静态属性。 ...同样的结果,可以引申到struts2,和其他...在多线程的环境下,是否存在静态变量不安全的问题。 ...
  • 其中askedCount 是静态变量多线程访问导致askedCount 结果不对,因为静态变量再被多个线程修改时其实是修改的同一个变量 导致 在返回前值被修改。 改正方式是 把askedCount 声明成静态变量。 public static ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 333,740
精华内容 133,496
关键字:

多线程访问静态变量