首页 > 编程语言 > 详细

6.10Java线程同步_synchronized

时间:2021-06-10 23:42:41      阅读:30      评论:0      收藏:0      [点我收藏+]

6.10Java线程同步_synchronized

线程的同步的含义

线程的同步是指:

  • 在一个多线程环境下保证数据的准确性、安全性--->线程安全

  • 提升性能--->三高原则(高性能、高并发、高可用)

难点:

  • 线程的同步不够形象

  • 并发控制比较困难--->琢磨、分析、又快又好

什么是并发?

并发是指:

  • 同一个对象多个线程同时操作--->同一个银行账户取钱

Java线程不安全演示--->相同资源数、负数资源数
package iostudy.synchro;
?
/**
* 线程不安全的演示
* @since JDK 1.8
* @date 2021/6/10
* @author Lucifer
*/
public class UnsafeTestNo1 {
   public static void main(String[] args) {
?
       /*实例化实现类对象--->一份资源对象*/
       UnsafeWeb12306 unsafeWeb12306 = new UnsafeWeb12306();
?
       /*实例化多个代理商--->多个线程*/
       new Thread(unsafeWeb12306, "小马哥!").start();
       new Thread(unsafeWeb12306, "大马哥!").start();
       new Thread(unsafeWeb12306, "老马哥!").start();
       /*
       1、这样写线程会导致线程不安全,有负数的情况和重复值的情况
       2、可能会出现两个99和值-1、-2
        */
?
  }
}
?
/**
* 创建一个内部多线程类
*/
class UnsafeWeb12306 implements Runnable{
?
   /*设置资源数--->票数*/
   private int ticketNums = 99;
   /*开关*/
   private boolean flag = true;
?
   /*重写Runnable接口当中的run方法*/
   @Override
   public void run(){
?
       /*线程的实际流程*/
       while (flag){
           test();
      }
?
  }
?
   /**
    * 封装一个线程内部具体方法类
    */
   public void test(){
?
       /*判断资源数*/
       if (ticketNums<0){
           /*开关关闭*/
           flag = false;
           /*结束方法*/
           return;
      }
?
       /*模拟延时*/
       try {
           Thread.sleep(200);
      }catch (InterruptedException e){
           System.out.println(e.getMessage());
           e.printStackTrace();
      }
?
       /*打印当前线程对象信息--->获取当前线程方法*/
       System.out.println(Thread.currentThread().getName() + "--->" + ticketNums--);
?
  }
}

说明:

出现负数票数情况

这里面涉及到边界值的概念

  • 同一时间片a、b、c三个线程都进入到多线程环境中(没有线程池)

  • b先进入,持有资源等待

  • b先拿走资源--->默认用户线程要执行完毕

  • a、c也需要执行完毕,只能拿走0、-1

关键点是没有控制最后一份资源而jvm默认所有线程不经过设置都是用户线程

出现相同票数的情况
  • new一个新生状态的线程的时候会开辟一个工作空间

  • 每一个线程的工作空间只与主存交互,各线程之间不存在数据交互

  • 在主存数据发生修改之前有两个线程与主存的数据进行交互,同时从主存拷贝值拿到工作空间进行处理导致出现两个一样的值

银行取款线程不安全
package iostudy.synchro;
?
/**
* 模拟银行取款线程不安全的情况
* 1、同一账户
* 2、多人同时操作
* 同时取出
* 一边取出一边存入
* 会造成数据的不一致
* @since JDK 1.8
* @date 2021/6/10
* @author Lucifer
*/
public class UnsafeTestNo2 {
   public static void main(String[] args) {
       /*创建资源类对象*/
       Account account = new Account(100, "彩礼");
?
       /*两个代理类对象--->三个参数(账户、取出数目、取出的人员*/
       Drawing you = new Drawing(account, 80,  "你");
       Drawing she = new Drawing(account, 90, "她");
?
       /*调用start方法--->就绪状态*/
       you.start();
       she.start();
?
  }
}
?
/**
* 创建一个账户类--->资源类
* @since JDK 1.8
* @date 2021/6/10
* @author Lucifer
*/
class Account{
?
   /*定义资源属性*/
   int money; //金额
   String name; //名称字符串
?
   /*创建构造器*/
   public Account(int money, String name) {
       this.money = money;
       this.name = name;
  }
}
?
/**
* 模拟提款机提款类--->多线程
* @since JDK 1.8
* @date 2021/6/10
* @author Lucifer
*/
class Drawing extends Thread{
?
   /*创建实现类对象--->面向对象的思想*/
   Account account; //取出的账户
   int drawingMoney; //取出的钱数
   int pocketTotal; //取出的钱的总数
?
   /*创建构造器,将属性定义为参数*/
   public Drawing(Account account, int drawingMoney, String name) {
       super(name); //线程的名称
       this.account = account;
       this.drawingMoney = drawingMoney;
  }
?
   /*重写run方法--->线程的具体实现*/
   @Override
   public void run() {
?
       /*在存钱和取钱的时候加入条件*/
       if (account.money-drawingMoney<0){
           /*结束方法*/
           return;
      }
?
       /*模拟取款的网络延迟*/
       try {
           Thread.sleep(1000);
      }catch (InterruptedException e){
           System.out.println(e.getMessage());
           e.printStackTrace();
      }
       /*
       理论上说加了判断就会控制结果
       但是实际上不会,这个需要对资源+锁实现控制的效果
        */
?
       /*账户的金额-取出的金额*/
       account.money -= drawingMoney;
       /*口袋中的金额+取出的钱*/
       pocketTotal += drawingMoney;
?
       /*因为继承了父类所以可以直接用this--->获取线程的名称*/
       System.out.println(this.getName() + "--->账户余额为:" + account.money);
       System.out.println(this.getName() + "--->身上余额为:" + pocketTotal);
?
  }
}
多线程操作容器保证数据不被丢失、覆盖
package iostudy.synchro;
?
import java.util.ArrayList;
import java.util.List;
?
/**
* 线程不安全:容器操作
* @since JDK 1.8
* @date 2021/6/10
* @author Lucifer
*/
public class UnsafeTestNo3 {
   public static void main(String[] args) {
?
       /*新建容器*/
       List<String> list = new ArrayList<String>();
?
       /*开启一万个线程*/
       for (int i=0; i<10000; i++){
           /*使用lambda表达式进行添加*/
           new Thread(() -> {
               list.add(Thread.currentThread().getName());
          }).start();
      }
?
       /*打印容器结果*/
       System.out.println(list.size());
       /*
       其结果是5105,并没有到1W条数据
       这是线程不安全的具体表现
       不是所有的情况下都需要考虑线程安全
       1、对数据存在"改"的行为--->控制
       2、存在读--->拷贝,不需要保证线程安全
        */
?
  }
}

 

6.10Java线程同步_synchronized

原文:https://www.cnblogs.com/JunkingBoy/p/14872838.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!