自定义线程类中的实例变量针对其他线程可以有共享与不共享之分,这在多个线程之间进行交互时是很重要的一个技术点。

图 1 所示为不共享数据的示例,图 2 所示为共享数据的示例。

例 1
如图 1 所示,在不共享数据时每个线程都拥有自己作用域的变量,且多个线程之间相同变量名的值也不相同。下面创建一个示例演示这种特性。

首先创建自定义的线程类 MyThread, 代码如下:

public class MyThread extends Thread {private int count=5;public xianc(String name){super();this.setName(name);//设置线程名称}public void run(){super.run();while(count>0){count--;System.out.println("由"+this.currentThread().getName()+"计算,count="+count);}}}

如上述代码所示,MyThread 线程的代码非常简单。下面编写代码在主线程中创建 3 个 MyThread 线程,并启动这些线程。具体代码如下:

public class Test
{public static void main(String[] args){ MyThread a=new MyThread("A"); MyThread b=new MyThread("B"); MyThread c=new MyThread("C"); a.start(); b.start(); c.start(); }
}

运行主线程将看到图 1 所示效果。从如下所示的运行结果可以看出,程序一共创建了 3 个线程,每个线程都有各自的 count 变量,自己减少自己的 count 变量的值。这样的情况就是变量不共享,此实例并不存在多个线程访问同一个实例变量的情况。

由 B 计算,count=4
由 B 计算,count=3
由 B 计算,count=2
由 B 计算,count=1
由 B 计算,count=0
由 C 计算,count=4
由 C 计算,count=3
由 C 计算,count=2
由 C 计算,count=1
由 C 计算,count=0
由 A 计算,count=4
由 A 计算,count=3
由 A 计算,count=2
由 A 计算,count=1
由 A 计算,count=0

例 2
如果想实现多个线程共同对一个变量进行操作的目的,该如何设计代码呢?这时就必须使用共享数据的方案。共享数据的情况就是多个线程可以访问同一个变量,比如在实现投票功能的软件时,多个线程可以同时处理同一个人的票数。

下面通过一个示例来看一下数据共享情况:

public class MyThread extends Thread {private int count=5; @Override public void run(){ super.run(); count--; //此示例不要用for语句,因为使用同步后其他线程就得不到运行的机会了, //一直由一个线程进行减法运算 System.out.println("由 "+this.currentThread().getName()+" 计算,count="+count); }}

编写代码在主线程中创建 5 个 MyThread 线程,并启动这些线程。具体代码如下:

public class Test {public static void main(String[] args){ MyThread mythread=new MyThread(); Thread a=new Thread(mythread,"A"); Thread b=new Thread(mythread,"B"); Thread c=new Thread(mythread,"C"); Thread d=new Thread(mythread,"D"); Thread e=new Thread(mythread,"E"); a.start(); b.start(); c.start(); d.start(); e.start();}
}

运行主线程将看到如下所示的效果。从运行结果中可以看到,线程 A 和 B 打印出的 count 值都是 3,说明 A 和 B 同时对 count 进行处理,产生了“非线程安全”问题,但我们想要得到的打印结果却不是重复的,而是依次递减的。

由 A 计算,count=3
由 D 计算,count=1
由 C 计算,count=2
由 B 计算,count=3
由 E 计算,count=0

在某些 JVM 中,i-- 的操作要分成如下3步:
取得原有 i 值。
计算 i-1。
对 i 进行赋值。

在这 3 个步骤中,如果有多个线程同时访问,那么一定会出现非线程安全问题。

其实这个示例就是典型的销售场景:5 名销售员,每名销售员卖出一件货品后不可以得出相同的剩余数量,必须在每一名销售员卖完一件货品后其他销售员才可以在新的剩余物品数上继续减1操作。这时就需要使多个线程之间进行同步,也就是用按顺序排队的方式进行减1操作。更改代码如下:

public class MyThread extends Thread {private int count=5; @Override synchronized  public void run(){ super.run(); count--; //此示例不要用for语句,因为使用同步后其他线程就得不到运行的机会了, //一直由一个线程进行减法运算 System.out.println("由 "+this.currentThread().getName()+" 计算,count="+count); }}

再次运行程序,就不会出现值一样的情况了,如下所示。

由 A 计算,count=4
由 D 计算,count=3
由 E 计算,count=2
由 C 计算,count=1
由 B 计算,count=0

通过在 run() 方法前加 synchronized 关键字,使多个线程在执行 run() 方法时,以排队的方式进行处理。当一个线程调用 run() 前,先判断 run() 方法有没有被上锁,如果上锁,说明有其他线程正在调用 run()方法,必须等其他线程对 run() 方法调用结束后才可以执行 run()方法。这样也就实现了排队调用 run() 方法的目的,达到了按顺序对 count 变量减 1 的效果。

synchronized 可以在任意对象及方法上加锁,而加锁的这段代码称为“互斥区” 或“临界区”。

当一个线程想要执行同步方法里面的代码时,线程首先尝试去拿这把锁,如果能够拿到锁,那么这个线程就可以执行 synchronize 里面的代码。如果不能拿到锁,那么这个线程就会不断地尝试拿锁,直到能够拿到为止,而且有多个线程同时去争抢这把锁。

Java多线程之间访问实例变量相关推荐

  1. Java多线程编程系列-实例变量和线程安全

    导语   上面说到了多线程的简单实现,编写了几个入门的小例子,这里我们来研究一下关于实例变量和线程安全的问题.在自定义的线程类中的实例变量针对其他线程可以有共享和不共享之分,下多个线程之间进行交互的时 ...

  2. 7、在对象内部尽量直接访问实例变量

    本文概要: 1.首先给出结论是:除了几种特殊情况外,在读取实例变量的时候采用直接访问的形式,而在设置实例变量的时候通过属性来做. 2.讲解了使用getter.setter的好处. 3.列举了几种上面提 ...

  3. 在对象内部尽量直接访问实例变量 --Effictive Objective-C 抄书

    在对象之外访问实例变量时,应该总是通过属性来做.在那么在对象内部访问实例变量的时候,又该如何呢? 这是 OCer们一直激烈讨论的问题.有人认为,无论什么情况,都应该通过属性来访问实例变量;也有人说,& ...

  4. java 并发变量_二、Java多线程编程 (对象及变量的并发访问)

    非线程安全 多个线程对同一个对象中的实例变量进行并发操作时会出现值被更改.值不同步的情况,进而影响程序的执行流程. 线程安全 线程安全就是获得实例变量的值是经过同步处理的.不会出现被更改不同步的情况. ...

  5. Java 多线程之间通讯(面试概念解答三)

    多线程之间通讯 多线程之间如何实现通讯? wait().notify.notifyAll()方法 wait与sleep区别? JDK1.5-Lock Lock 接口与 synchronized 关键字 ...

  6. java程序如何访问成员变量,java如何访问成员变量

    通过Class对象的getField()方法,可以获得这种包含的所有或指定的成员变量Field,Filed提供以下两种方法阅读和设定成员变量值 1.getxx(Objectobj): 获得obj对象的 ...

  7. Java通过反射访问成员变量

    通过下列任意一个方法访问成员变量时将返回 Field 类型的对象或数组. getFields()getField(String name)getDeclaredFields()getDeclaredF ...

  8. Java多线程游戏仿真实例分享

    这是一篇学习分享博客,这篇博客将会介绍以下几项内容: 1.如何让一个程序同时做多件事?(多线程的创建.多线程的应用) 2.如何让小球在画面中真实地动起来?(赋予小球匀速直线.自由落体.上抛等向量运动) ...

  9. Java基础---类变量和实例变量

    类变量和实例变量 成员变量:把类内.方法体外的变量称为成员变量. package com.chen.offer.BiliBili;/*** @author chenshimiao* @Email 16 ...

最新文章

  1. 聚类和EM算法——K均值聚类
  2. #1045 无法登录 MySQL 服务器 phpmyadmin
  3. 告别“臃肿”,选择微服务(文末福利)
  4. Git 中.gitignore 使用和.gitignore 无效的解决方法
  5. 为什么不能在init和dealloc函数中使用accessor方法
  6. 安装mysql出现错误_安装Mysql时出现错误及解决办法
  7. CSS---网络编程
  8. android打包apk、apk签名及360加固工具的使用
  9. redis服务的部署
  10. Java基础---认识IO流---字节流、字符流---缓冲流---转换流
  11. if语句中的赋值与判断
  12. 【3】Keras.applications包,一堆可以复用的深度学习模型库
  13. 协鑫集成等四家公司被退出欧盟MIP协议
  14. (附代码)手写滑动验证码,完整代码开放
  15. 2021年高压电工考试题及高压电工理论考试
  16. cmos逻辑门传输延迟时间_MOS管以及简单CMOS逻辑门电路原理图解析
  17. snaker工作流核心表学习
  18. python批量请求url_python批量请求注册接口爬虫相关问题记录
  19. JavaScript 剪贴板
  20. C++日期计算器的实现

热门文章

  1. OS_CORE.C(3)
  2. 五分钟搞定 Linux 文档全部知识,就看这篇文章
  3. (转载)C#:Enum、Int和String的互相转换,枚举转换
  4. [LintCode] Trailing Zeroes 末尾零的个数
  5. 后缀自动机序列自动机综合
  6. 一个简单的blog系统(十一) 增加文章检索功能
  7. 总结 | 如何测试你自己的 RubyGem
  8. OSX操作技巧:快速锁定系统(类似Windows+L)
  9. 【译】在ASP.Net和IIS中删除不必要的HTTP响应头
  10. ESP8266烧写时的各种参数设置