博客信息

多线程安全问题(同步函数的锁是this、静态同步函数的锁是Class对象、死锁)

发布时间:『 2019-05-29 22:25』  博客类别:java基础  阅读(735)

同步函数的锁是this

将卖票的例子由原来的同步代码块改成同步函数

小李飞刀_线程

 

接下来用代码进行验证同步函数的锁是this这一结论

package com.javaxl.thread;


/**
 * @author 小李飞刀
 * @site www.javaxl.com
 * @company
 * @create  2019-05-29 11:09
 *
 * 多线程的安全问题
 *
 */
public class Demo2 {
    public static void main(String[] args) {
        Ticket z = new Ticket();
        Thread t1 = new Thread(z);
        Thread t2 = new Thread(z);
        t1.start();

//        这样能确保两个线程错开执行
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("------------------------------------");
        z.flag = false;
        t2.start();

//        用来论证线程安全的问题
//        Thread t3 = new Thread(z);
//        Thread t4 = new Thread(z);
//        t3.start();
//        t4.start();
    }
}

class Ticket implements Runnable{
    private int num = 10000000;
    private Object obj = new Object();
//    制造两个线程在跑一个同步代码块的假象
//      同步代码块上的锁暂定为obj  我们发现会出现0这个数字,出现了并发问题
//    造成上面并发问题的原因就在于多线程用的不是同一把锁,也就意味着同步函数上的锁不是obj,这时我们在将同步代码块上的obj改成this
    boolean flag = true;
    @Override
    public void run() {
      if(flag){
          synchronized (obj){
              while (true){
                  if(num>0){
//                      try {
//                          Thread.sleep(60);
//                      } catch (InterruptedException e) {
//                          e.printStackTrace();
//                      }
                      System.out.println(Thread.currentThread().getName() + "同步代码块..sale........"+ num--);
                  }
              }
          }
      }else {
          while (true){
              show();
          }
      }
    }

    public synchronized void show(){
        if (num > 0){
//            try {
//                Thread.sleep(60);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
            System.out.println(Thread.currentThread().getName() + "...sale......同步函数................"+ num--);
        }
    }
}

结果

小李飞刀_线程


小李飞刀_线程

 

两个线程被锁给锁定,这两个线程操作共享数据,如果线程不是被同一把锁控制

那么两个线程还是可以同时操作同步代码块的内容,依然会引发并发问题。

静态同步函数的锁是Class对象

如果同步函数被静态修饰后,使用的锁什么呢?

 

通过验证,发现不再是this,因为静态方法中也不可以定义this

 

静态进内存时,内存中没有本类对象,但是一定有该类对应的字节码文件对象;

类名.class 该对象的类型是class

 

静态的同步函数,所用的锁是该方法所在类的字节码文件对象。类名.class

 

我们反过头再来看单例模式的懒汉式为什么这么写?

小李飞刀_线程

 

死锁

将上面例子简单改动

小李飞刀_线程

 

简单的死锁案例

小李飞刀_线程

相关代码

package com.javaxl.thread;

/**
 * @author 小李飞刀
 * @site www.javaxl.com
 * @company
 * @create  2019-05-29 21:12
 *
 * 死锁
 */
public class Demo3 {
    public static void main(String[] args) {
        SiThread s = new SiThread();
        Thread t1 = new Thread(s);
        Thread t2 = new Thread(s);
        t1.start();
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        s.flag = false;
        t2.start();
    }
}



class MyLock{
    static Lock locka = new Lock();
    static Lock lockb = new Lock();
}

class  Lock{

}

class SiThread implements Runnable{
    boolean flag = true;
    @Override
    public void run() {
        if(flag){
            while (true){
                synchronized (MyLock.locka){
                    System.out.println("if locka");
                    synchronized (MyLock.lockb){
                        System.out.println("if lockb");
                    }
                }
            }
        }else {
            while (true){
                synchronized (MyLock.lockb){
                    System.out.println("else lockb");
                    synchronized (MyLock.locka){
                        System.out.println("else locka");
                    }
                }
            }
        }
    }
}





关键字:     Java基础       多线程安全  

备案号:湘ICP备19000029号

Copyright © 2018-2019 javaxl晓码阁 版权所有