1.线程不安全的问题分析

当多线程并发访问同一个资源对象的时候,可能出现线程不安全的问题.但是,我们分析打印的结果,发现没有问题:
为了让问题更明显:
    Thread.sleep(10);//当前线程睡10毫秒,当前线程休息着,让其他线程去抢资源.  经常用来模拟网络延迟.              
----------------------------------------------------------

在程序中并不是使用Thread.sleep(10)之后,程序才出现问题,而是使用之后,问题更明显.

//线程对象
class Apple1 implements Runnable {private int num = 50;//共享资源,50个苹果public void run() {for (int i = 0; i < 50; i++) {if (num > 0) {//模拟网络延迟try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}/*** 出现0,-1的情况* 当B,C,A 3个线程都到这里来了,然后B,C,A现在在这里睡了,后来B线程醒来抢到了执行权打印结果1,然后num-1=0;* 接着B再醒来执行打印的时候num此时为0,所以打印为0,接着num-1=-1;* 最后A再醒过来执行打印的时候num此时为-1,所以打印-1;* */System.out.println(Thread.currentThread().getName() + "吃了编号为"+ num-- + "的苹果");}}}}public class ThreadDemo7 {public static void main(String[] args) {//创建线程类对象,启动3个线程Apple1 apple = new Apple1();new Thread(apple, "小A").start();new Thread(apple, "小B").start();new Thread(apple, "小C").start();}
}

截取部分打印结果(由于电脑配置可能不同,所以打印结果不一定相同,没出现结果的说明电脑配置太好了,可以把50改为500或5000):


很明显,不应该出现0,-1这些情况,出现这种情况的原因就是因为

要解决上述多线程并发访问多一个资源的安全性问题:
解决方案:保证打印苹果编号和苹果总数减1操作,必须同步完成.
               比如A线程进入操作的时候,B和C线程只能在外等着,A操作结束,A和B和C才有机会进入代码去执行.
-------------------------------------------------------------------------------
方式1:同步代码块
方式2:同步方法
方式3:锁机制(Lock)

2.同步代码块

语法:
synchronized(同步锁)
{
     需要同步操作的代码
}

---------------------------------------------------
同步锁:
为了保证每个线程都能正常执行原子操作,Java引入了线程同步机制.
同步监听对象/同步锁/同步监听器/互斥锁:
对象的同步锁只是一个概念,可以想象为在对象上标记了一个锁.
Java程序运行使用任何对象作为同步监听对象,但是一般的,我们把当前并发访问的共同资源作为同步监听对象.
注意:在任何时候,最多允许一个线程拥有同步锁,谁拿到锁就进入代码块,其他的线程只能在外等着.

//线程对象
class Apple1 implements Runnable {private int num = 50;//共享资源,50个苹果public void run() {for (int i = 0; i < 50; i++) {//同步代码块synchronized (this) {  //this就是这里的同步锁Apple1的对象,该对象属于多线程共享资源if (num > 0) {//模拟网络延迟try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+ "吃了编号为" + num-- + "的苹果");}}}}}public class ThreadDemo7 {public static void main(String[] args) {//创建线程类对象,启动3个线程Apple1 apple = new Apple1();new Thread(apple, "小A").start();new Thread(apple, "小B").start();new Thread(apple, "小C").start();}
}

3.同步方法

使用synchronized修饰的方法,就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外等着.
synchronized   public    void  doWork(){
     ///TODO
}

同步锁是谁:
      对于非static方法,同步锁就是this.  
      对于static方法,我们使用当前方法所在类的字节码对象(Apple2.class).

//线程对象
class Apple2 implements Runnable {private int num = 50;//共享资源,50个苹果public void run() {for (int i = 0; i < 50; i++) {eat();}}//同步方法synchronized private void eat() {  if (num > 0) {//模拟网络延迟try {Thread.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+ "吃了编号为" + num-- + "的苹果");}}}public class ThreadDemo8 {public static void main(String[] args) {//创建线程类对象,启动3个线程Apple2 apple = new Apple2();new Thread(apple, "小A").start();new Thread(apple, "小B").start();new Thread(apple, "小C").start();}
}


注意:

不要使用synchronized修饰run方法,修饰之后,某一个线程就执行完了所有的功能. 好比是多个线程出现串行.
解决方案:把需要同步操作的代码定义在一个新的方法中,并且该方法使用synchronized修饰,再在run方法中调用该新的方法即可.

synchronized的好与坏:
好处:保证了多线程并发访问时的同步操作,避免线程的安全性问题.
缺点:使用synchronized的方法/代码块的性能比不用要低一些.
建议:尽量减小synchronized的作用域.

4.同步锁(Lock)

Lock机制提供了比synchronized代码块和synchronized方法更广泛的锁定操作,同步代码块/同步方法具有的功能Lock都有,除此之外更强大,更体现面向对象.JDK1.5才出现的

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;//线程对象
class Apple3 implements Runnable {private int num = 50;//共享资源,50个苹果private final Lock lock = new ReentrantLock();//创建一个锁对象public void run() {for (int i = 0; i < 50; i++) {eat();}}private void eat() {  lock.lock();  //一进方法就要获取锁try {if (num > 0) {//模拟网络延迟Thread.sleep(10);System.out.println(Thread.currentThread().getName()+ "吃了编号为" + num-- + "的苹果");}} catch (InterruptedException e) {e.printStackTrace();} finally{lock.unlock();   //最后必须释放锁}}}public class ThreadDemo9 {public static void main(String[] args) {//创建线程类对象,启动3个线程Apple3 apple = new Apple3();new Thread(apple, "小A").start();new Thread(apple, "小B").start();new Thread(apple, "小C").start();}
}

java多线程之线程同步问题相关推荐

  1. Java多线程之线程同步机制(锁,线程池等等)

    Java多线程之线程同步机制 一.概念 1.并发 2.起因 3.缺点 二.三大不安全案例 1.样例一(模拟买票场景) 2.样例二(模拟取钱场景) 3.样例三(模拟集合) 三.同步方法及同步块 1.同步 ...

  2. java多线程采集+线程同步-【多线程数据采集之四】

    前些日子讲解了java数据抓取, 今天就讲解最核心的. java多线程数据抓取. java多线程采集+数据同步+线程同步[多线程数据采集之四] 主要讲解多线程抓取,多线程同步,多线程启动,控制等操作. ...

  3. Java多线程(线程同步)

    多线程编程很容易出现"错误情况",这是由系统的线程调度具有一定的随机性造成的,不过即使程序偶然出现问题,那也是由于编程不当引起.使用多个线程访问同一个数据时很容易出现此类状况,因此 ...

  4. Java多线程编程——线程同步与线程安全问题及synchronized关键字

    在多线程环境下,我们常常需要让多个线程同时去操作同一资源.在某些情况下,这种情形会导致程序的运行结果出现差错.专业上的,当多个线程在执行同一段代码的时候,每次的执行结果和单线程执行的结果都是一样的,不 ...

  5. java多线程:线程同步synchronized(不同步的问题、队列与锁),死锁的产生和解决

    0.不同步的问题 并发的线程不安全问题: 多个线程同时操作同一个对象,如果控制不好,就会产生问题,叫做线程不安全. 我们来看三个比较经典的案例来说明线程不安全的问题. 0.1 订票问题 例如前面说过的 ...

  6. Java 多线程和线程同步总结

    转载:JAVA多线程实现和线程同步总结 1.JAVA多线程实现方式 JAVA多线程实现方式主要有三种:继承Thread类.实现Runnable接口.使用ExecutorService.Callable ...

  7. Java多线程之线程同步

    线程同步 线程同步:当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作, 其他线程才能对该内存地址进行操作,而其他线程又处于等待状态,实现线程同步的方法有很多. ...

  8. java多线程、线程同步与线程池

    1. 线程的基本概念 1.1 进程 任何的软件存储在磁盘中,运行软件的时候,OS使用IO技术,将磁盘中的软件的文件加载到内存,程序在能运行. 进程的概念 : 应用程序(typora,word,IDEA ...

  9. Java多线程:线程同步(3)- synchronized关键字

最新文章

  1. Hibernate框架第二天
  2. 02dayC语言数据类型
  3. WDS使用捕获映像制作企业自定义映像
  4. 模拟退火求函数最值问题求解
  5. java警惕自增的陷阱
  6. 论文浅尝 | ICLR 2020 - 图神经网络的预训练策略
  7. python数据格式化后导入数据库_MySQL导入格式化数据
  8. C++ 无法打开包括文件“mysql.h“: No such file or directory
  9. PSV 2000 3.68降级3.60固化教程
  10. html+css网页开发 之 头部导航条(logo、导航栏、搜索框)
  11. 实现 Git 目录权限控制
  12. storm风暴英雄 tempo_《绝地求生》Tempo Storm北美黑马,掌控战场
  13. windows用户验证
  14. 安卓开发——视频播放器
  15. py3_VSCode 配置 Python 环境以及初识 Python 正则表达式
  16. 计算机技术在建模中的作用,谈计算机在数学建模中的作用
  17. 基于Quartus II 软件(VHDL)设计
  18. 解决dotnetfx35和dotnetfx35SP1在线安装慢的问题
  19. 高德地图上半年公共交通报告:公交都市排行上海、厦门双榜首
  20. r语言npsurv_R语言常用包分类总结 - osc_mf6gua6n的个人空间 - OSCHINA - 中文开源技术交流社区...

热门文章

  1. 2019年,这5个UI设计趋势正在流行!
  2. vue项目在IE浏览器和360兼容模式下页面不显示问题,亲测有效
  3. 整理各种Vue项目在IE浏览器白屏报错 SCRIPT1002:语法错误
  4. 基于springboot客户管理系统
  5. linux 休眠定时唤醒_LINUX 休眠唤醒问题
  6. source profile之后关闭终端,在打开终端nvcc -V和java -verson没有输出
  7. NLP实战:使用机器/深度学习做文本分类
  8. 渗透某公众号思路分享
  9. 行为识别之C3D-network
  10. 使用VMware安装centos 7 图形化界面