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

不共享数据的情况

  如图在进行数据操作的时候,相互之间的数据不会产生影响,都在自己的一块内存中进行操作。

下面就通过一个小例子来看看不共享情况
自定义实现类

public class MyThread extends Thread {private int count = 5;public MyThread(String name){super();this.setName(name);}@Overridepublic void run() {super.run();while (count>0){count--;System.out.println("由 "+currentThread().getName()+" 计算,count="+count);}}
}

运行类

public class Run {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();}
}

运行结果

  通过上面的例子可以看到,一共创建了3个线程,每个线程都有各自的count变量,自己减少自己的count变量值,这样所实现的变量就是不共享的,也就是说在JVM分配给线程独立的内存中进行运行。所以不会存在多个线程共同访问同一个变量的情况。

  下面就来看看多个线程访问同一个变量的情况

共享数据情况

  共享数据的情况就是多个线程可以访问同一个变量,例如在实现抢票软件功能的时候,多线程共同处理同一个火车上的火车票操作。

共享数据小例子
创建自定义线程

public class MyThread extends Thread {private int count = 5;@Overridepublic void run() {super.run();count--;System.out.println("由 "+currentThread().getName()+ " 计算, count = "+count);}
}

测试类

public class Run {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();}
}

测试结果

  从上面的结果中可以看到有些线程处理的数据居然是同一个数据,还有一个情况是每次运行的结果是不一样的。从这个角度上看对于count变量的访问并不是安全的在之前的之前的博客中分析过这种情况出现的原因。这里简单的说一下操作步骤

  • 1、获取原有的值
  • 2、计算i-1的值
  • 3、对i进行赋值

在这个三个步骤任意的一个步骤都有可能出现问题,并且导致结果不同。有兴趣的读者可以研究一下或者看看博主的高并发系列。那么如果我们将自定义的Thread修改为如下,还会出现错误么!!

public class MyThread extends Thread {private int count = 5;@Overridesynchronized public void run() {super.run();count--;System.out.println("由 "+currentThread().getName()+ " 计算, count = "+count);}
}

运行结果

会看到结果是正确的。也就是说加入了synchronized关键字之后在线程进入run()方法之前会以排队的方式进行处理,当一个线程调用run方法之前首先判断run方法是不是被锁上了,如果被锁则说明有其他线程正在处理这个数据,那就要等到这个线程处理完成之后才会轮到排队线程进行处理。而这段被synchronized关键字标注的代码块被称为是互斥区或者是临界区。

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

面试题

一个局部变量i=1,两个线程同时执行,是否是线程安全的?

情况一 属于自定义线程类中的变量

public class MyThread extends Thread {private int i = 5;@Overridepublic void run() {i--;System.out.println(i);}
}

测试类

public class Test {public static void main(String[] args) {MyThread t1 = new MyThread();MyThread t2 = new MyThread();t1.start();t2.start();}
}

情况二 属于自定义线程类中的某个方法的局部变量

public class MyThread extends Thread {public void print(){int a = 5;a--;System.out.println(currentThread().getName() + "  "+a);}@Overridepublic void run() {print();}
}

情况三 属于继承了Runnable接口的线程类变量

public class MyRunnable implements Runnable {private int i = 5;private String name ;public MyRunnable(String name){this.name = name;}@Overridepublic void run() {System.out.println("name " + name +getClass().getName()+ "   "+i--);}
}

测试类

public class Run {public static void main(String[] args) throws InterruptedException {MyRunnable r1 = new MyRunnable("TE");Thread t1 = new Thread(r1);Thread t2 = new Thread(r1);t1.start();TimeUnit.SECONDS.sleep(10);t2.start();}
}

有一个共享变量如何保证线程安全 ?

  • 使用synchronize关键字
  • 使用显式锁
  • 使用单一对象模式

总结

  这篇博客主要分析了两件事情,也就是结尾的时候所提供的两个面试题。怎样实现多线程线程安全是很多人在研究的一个课题,在分布式系统中,在高并发场景下,这些都是不可避免的问题。

Java多线程编程系列-实例变量和线程安全相关推荐

  1. 详解Java多线程编程中LockSupport类的线程阻塞用法

    转载自  详解Java多线程编程中LockSupport类的线程阻塞用法 LockSupport类是Java6(JSR166-JUC)引入的一个类,提供了基本的线程同步原语.LockSupport实际 ...

  2. C#多线程编程系列(二)- 线程基础

    目录 C#多线程编程系列(二)- 线程基础 1.1 简介 1.2 创建线程 1.3 暂停线程 1.4 线程等待 1.5 终止线程 1.6 检测线程状态 1.7 线程优先级 1.8 前台线程和后台线程 ...

  3. Java多线程编程系列-多线程基础

    导语   如果想要深入的了解一个东西就需要不断的接近他,这样才能了解到其核心的东西.这个系列就来了解一下Java多线程.开始入坑吧!   在入坑之前先来看一个例子!! public class Tes ...

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

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

  5. Java多线程之间访问实例变量

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

  6. C#多线程编程系列(三)- 线程同步

    目录 1.1 简介 1.2 执行基本原子操作 1.3 使用Mutex类 1.4 使用SemaphoreSlim类 1.5 使用AutoResetEvent类 1.6 使用ManualResetEven ...

  7. java 模拟停车_Java多线程编程小实例模拟停车场系统

    下面分享的是一个Java多线程模拟停车场系统的小实例(Java的应用还是很广泛的,哈哈),具体代码如下: Park类 public class Park { boolean []park=new bo ...

  8. C#多线程编程系列(一)- 简介

    目录 系列大纲 一.前言 二.目录结构 四.章节结构 五.相关链接 系列大纲# 目前只整理到第二章,线程同步,笔者后面会慢慢更新,争取能把这本书中精华的知识都分享出来. C#多线程编程系列(一)- 简 ...

  9. Java并发编程最佳实例详解系列

    Java并发编程最佳实例详解系列: Java并发编程(一)线程定义.状态和属性 Java并发编程(一)线程定义.状态和属性 线程是指程序在执行过程中,能够执行程序代码的一个执行单元.在java语言中, ...

最新文章

  1. 构建Dubbo-2.0.7源码
  2. bleve搜索引擎源码分析之索引——mapping真复杂啊
  3. pytorch安装实录(win10+cuda8+pycharm+anaconda)
  4. vue 的常用模块安指令(持续记录)
  5. java 柱状图jar_GitHub - mafulong/NetworkExper: 计网实验,抓包,java,jigloo界面开发,柱状图,文件自定义保存...
  6. 用汇编的眼光看C++(之class构造、析构)
  7. 线性代数学习之对称矩阵与矩阵的SVD分解
  8. Axure 教程 | 微博分享
  9. VCS/Questa SIM 使用流程及Makefile
  10. java.lang.IllegalArgumentException: Address 127.0.0.1:5672:5672 seems to contain an unquoted IPv6
  11. ssh-keygen命令使用
  12. 十八个著名的心理学效应,生活中你一定用的到
  13. 稿子文字左右对称翻转_Matlab/OpenCV (2021-09-06)
  14. bootstrap模态框弹出居中显示
  15. 从0开始学习python7:Python中词频统计以及sort的排序用法
  16. 找对英语学习方法的第一本书之:标准发音
  17. Spring Boot从0开始学的个人笔记11 --安全security
  18. sendmail命令的使用
  19. Unity手游实战:从0开始SLG——ECS战斗(四)实战ECS架构和优化
  20. python大数据培训班学费

热门文章

  1. java多线程通信基础(面向厕所编程)
  2. String,StringBuilder, StringBuffer
  3. FastRoute - 快速请求路由
  4. eNSP模拟器RIP2动态路由,DHCP服务,ACL流控,组合使用的拓扑网络
  5. RFID能否让实体零售业度过“寒冬”?
  6. latex/Xelatex书籍排版总结---顺便附上一本排好的6寸android书…
  7. 有些车已经不能再买了!因为国五排放标准就要来了!
  8. 页面无法访问 css文件加载问题
  9. C语言printf 和 scanf 用法
  10. Cocos2d-x教程(28)-ttf 字体库的使用