美文网首页
多线程的安全问题(代码同步问题)

多线程的安全问题(代码同步问题)

作者: 东风谷123Liter | 来源:发表于2018-07-08 10:43 被阅读0次

通过分析,发现,打印出0,-1,-2的错票。
多线程出现安全问题!!!!

  • tick只有一份,多个线程共用这个tick;
  • 当多条语句在操作一个线程共享数据时,一个线程对多条语句只执行了一部分,还没执行完另一个线程已经开始执行共享代码块!!
  • 解决办法:将共享代码块加上一个锁,也叫同步代码块;——— cynchronized
  • 格式:synchronized(对象){ 代码块 };对象:只要是对象就可以,可以用上帝(Object obj)
  • 锁原理:就是在同步代码块前设置一个标志位,代码块被线程执行时,标志位置0,代码块未被执行时,标志位置1.
  • 持有锁的线程可以在代码块中执行,没有锁的线程及时获取到了CPU资源也不能在同步中中执行!
  • 锁的弊端:未执行代码块的线程要不断重复的判断标志位,这会消耗资源,拖慢进程速度。

同步的前提:

    • 两个或两个以上的线程。
    • 必须时多个线程同时使用一个锁。
    • 必须保证同步代码只有一个线程在运行。

什么代码需要同步?

    • 方法:明确哪些代码块是多线程运行。
    • 明确共享数据。
    • 明确多线程运行代码中哪些语句是操作共享数据的。
  • 函数也可以封装代码,格式:public synchronized void add( **** ){ } ; 作为修饰符,放在前面。
    注意:在任何时候,你都可以用Thread.currentThread().getName()来获取当前线程的名字

发现存在代码安全问题:

/*
需求:
银行有一个金库。
有两个储户分别存300元,每次存100,存3次
*/
class Bank{
    private int sum;
    public void add(int n){
        sum = sum + n;
        try{Thread.sleep(10);}catch(Exception e){}
        System.out.println("sum = "+sum);
    }
}
class Cus implements Runnable{
    private Bank b = new Bank();
    public void run(){
        for(int x=0; x<3; x++){
            b.add(100);
        }
    }
}
class BankDemo{
    public static void main(String[] args){
        Cus c = new Cus();
        Thread t1 = new Thread(c);
        Thread t2 = new Thread(c);
        t1.start();
        t2.start();
    }
}
  • 结果: image.png
  • 解决问题:

/*
需求:
银行有一个金库。
有两个储户分别存300元,每次存100,存3次
*/
class Bank{
    private int sum;
    Object obj = new Object();
    public void add(int n){
        synchronized(obj){
            sum = sum + n;
            try{Thread.sleep(10);}catch(Exception e){}
            System.out.println("sum = "+sum);
        }
    }
}
class Cus implements Runnable{
    private Bank b = new Bank();
    public void run(){
        for(int x=0; x<3; x++){
            b.add(100);
        }
    }
}
class BankDemo{
    public static void main(String[] args){
        Cus c = new Cus();
        Thread t1 = new Thread(c);
        Thread t2 = new Thread(c);
        t1.start();
        t2.start();
    }
}
  • 结果:

    • image.png

同步函数:

    • 同步函数用的是哪一个锁?
    • 函数需要被对象调用,那么函数就都有一个所属对引用。就是this。
    • 所以同步函数使用的锁事this。
    /*
需求:
银行有一个金库。
有两个储户分别存300元,每次存100,存3次
*/
class Bank{
    private int sum;
    //Object obj = new Object();
    public synchronized void add(int n){   //同步函数!!
        //synchronized(obj){
            sum = sum + n;
            try{Thread.sleep(10);}catch(Exception e){}
            System.out.println("sum = "+sum);
        //}
    }
}
class Cus implements Runnable{
    private Bank b = new Bank();
    public void run(){
        for(int x=0; x<3; x++){
            b.add(100);
        }
    }
}
class BankDemo{
    public static void main(String[] args){
        Cus c = new Cus();
        Thread t1 = new Thread(c);
        Thread t2 = new Thread(c);
        t1.start();
        t2.start();
    }
}

一个小练习:

* /*
* 需求:现有两个线程:
* 一个线程在同步代码块中运行;
* 一个线程在同步函数中运行;
* 两个线程都在执行买票程序。
* */
* class Ticket implements Runnable{
*     private int tick = 1000;
*     Object obj = new Object();
*     boolean flag = true ;
*     public void run(){
*         if(flag){
*             while(true){
*                 synchronized(obj){  //synchronized( this ),解决0号票问题。
*                     if(tick >0){
*                         try{Thread.sleep(10);}catch(Exception e){}
*                         System.out.println(Thread.currentThread().getName()+"code.....sale "+ tick--);
*                     }
*                 }
*             }
*         }
*         else{
*             while(true){
*                 this.show();
*             }
*         }
*     }
*     public synchronized void show(){
*         if(tick >0){
*             try{Thread.sleep(10);}catch(Exception e){}
*             System.out.println(Thread.currentThread().getName()+"show.....sale "+ tick--);
*         }
*     }
* }
* class TickDemo{
*     public static void main(String[] args){
*         Ticket t = new Ticket();
*         Thread t1 = new Thread(t);
*         Thread t2 = new Thread(t);
*         t1.start();
*         try{Thread.sleep(10);}catch(Exception e){}  //解决办法
*         t.flag = false;  //问题的渊源!原因:主线程执行太快,这三条语句瞬间就执行完成;flag的作用完全没有体现出来,flag=true时同步代码块还没来的及执行,flag就等于false了,紧接着执行show( )函数;之后就一直为false了。
*         t2.start();
*     }
* }
  • 代码看似没问题,其实问题可大!所有线程都是由show( )同步函数执行完成的。如下:
  • image.png
  • 解决办法在代码中!!!
  • 之后有出现0号票!!!可怕!!
    • image.png
    • 解决:把同步代码块中obj对象换成this就OK了!
  • 如果同步函数被静态修饰时,使用的锁是什么呢?
    • 通过验证,发现不再是this,因为静态方法中也不可以定义this。
      • 原因:静态进内存时没有对象,只有类,也就是该类对应的字节码文件对象
      • 类名.class 该对象的类型是class。
    • 静态的同步方法,使用的锁事该方法所在类的字节码文件对象。类名.class

相关文章

  • 同步锁Lock

    用于解决多线程安全问题的方式:synchronized 隐式锁 同步代码块 同步方法 jdk1.5后新增 同步锁...

  • Java线程安全

    线程安全问题的概述 线程安全问题的代码实现 线程安全问题产生的原理 解决线程安全问题_同步代码块 同步代码块:sy...

  • java解决多线程安全的方式

    解决多线程安全问题的方式(加锁)包含以下几种: synchronized关键字:又包含同步代码块,同步方法 Loc...

  • 线程的基本语法

    线程同步[解决线程安全问题] 解决线程安全问题 线程同步方式一:同步代码 语法基本 synchronized (同...

  • 多线程的安全问题(代码同步问题)

    通过分析,发现,打印出0,-1,-2的错票。多线程出现安全问题!!!! tick只有一份,多个线程共用这个tick...

  • iOS 多线程技术有些啥,如何解决多线程带来的隐患

    有多线程就有因为多线程造成的数据安全问题(如何确保同一块共享内存在多线程下不发生数据错乱和数据安全问题) 线程同步...

  • 五 异常与多线程——第三节 线程同步机制

    1、线程安全问题的概述 多线程访问了共享的数据,就会产生线程安全问题 2、线程安全问题的代码实现 输出:会出现重复...

  • Java-单例模式-线程安全问题

    单例设计模式:懒汉式(延迟加载 等你需要的时候再创建对象 在多线程中会出现安全问题):解决安全问题 加了同步操作 ...

  • volatile关键字

    线程安全问题 Java多线程带来的一个问题是数据安全问题,判断一段Java代码是否有线程安全问题可从以下几点入手:...

  • 同步监视器锁定的释放问题

    在任何编程语言中,事关线程安全问题非常重要,而同步监测器是解决java多线程安全问题的关键,关于监测器锁定...

网友评论

      本文标题:多线程的安全问题(代码同步问题)

      本文链接:https://www.haomeiwen.com/subject/kytouftx.html