• 引言
  • Java多线程中的类锁
  • 1 注意区分类锁和对象锁的区别
  • Java中的死锁现象
  • 1 最低级的线程死锁现象
  • volatile关键字
  • 1 同步死循环问题
  • 2 解决死循环记住

1.引言

      在此篇博客中,主要介绍一下,在Java多线程中的:类锁,死锁,以及volatile关键字。

2.Java多线程中的类锁

在上一篇博客中我们使用了下面的代码:

public synchronized boolean saleTicket() throws Exception
    {   
        //代码
    }
在上篇博客中我们介绍了,这样其实就是给该方法加锁:加的是对象锁,对象就是this
注意:
    1.该方法不是静态方法,如果是静态方法呢?静态方法就不是this了。
    2.这很好理解,如果是静态方法,在私用该方法的时候,说不定都没有this对象
  • 现在我们把代码改成这样(方法变成了静态方法)
public synchronized static void saleTicket()
    {   
        System.out.println("我在卖票了");
    }

上述代码等价于

public class Ticket {
    public  static void saleTicket()
    {   
        synchronized (Ticket.class) {
        System.out.println("我在卖票了");

        }

    }
}
此时我们是给方法添加了一个类锁。

2.1 注意区分类锁和对象锁的区别

public class Ticket {
    public synchronized  static void saleTicket1()
    {   
        System.out.println("我在卖票了");            
    }
    public synchronized  void saleTicket2()
    {   
            System.out.println("我在卖票了");    
    }
}
注意:
    1.这两个方法给对象加的锁是不一样的,一个是类锁,一个是this对象锁
    2.当线程1访问saleTicket1方法的同时拿到类锁
    3.当线程2访问saleTicket2是要拿this对象锁(哪怕线程1未释放锁)。两者是不影响的

3. Java中的死锁现象

      在Java多线程编程当中,一定要避免死锁现象。死锁现象一产生很容易造成线程假死现象。这种错误是非常难排查的。

3.1 最低级的线程死锁现象

  • 代码如下
public class Ticket {
    private Object o1=new Object();
    private Object o2=new Object();
    public  void saleTicket1()
    {   
        synchronized (o1) {     
            System.out.println("拿到o1");
            synchronized (o2) {     
                System.out.println("拿到o2");
            }
        }
    }
    public  void saleTicket2()
    {
        synchronized (o2) { 
            System.out.println("拿到o2");
            synchronized (o1) { 
                System.out.println("拿到o1");
            }
        }

    }
}
1.如果线程1访问saleTicket1方法。线程2访问saleTicket2方法
2.线程1拿到o1锁,线程2拿到o2锁,此时线程1等待o2锁,线程2等待o1锁:导致死锁
3.线程死锁是程序设计时的bug,我们应该尽量避免死锁现象的产生

4.volatile关键字

关键字volatile解决的问题主要是:变量在多个线程间可见。

4.1 同步死循环问题

  • 首先我们创建一个打印字符串的类
public class PrintString {
    private boolean flag = true;
    public void setFlag(boolean flag) {
        this.flag = flag;
    }
    public void printString() {
        while (flag) {
            System.out.println("打印字符串");
        }
    }

}
  • 输入字符串的线程类
public class MyThread extends Thread {
    PrintString p;
    public MyThread(PrintString p) {
        this.p=p;
    }
    @Override
    public void run() {
        p.printString();    
    }

}
  • main函数
public class app {
    public static void main(String[] args) throws InterruptedException {
        PrintString p=new PrintString();
        MyThread td=new MyThread(p);
        td.start();
        Thread.sleep(5000);
        p.setFlag(false);
    }

}
  • 如果我们以服务器模式运行,这就是一个死循环-server

Java 三方调不到支付回调接口_java

4.2 解决死循环(记住)

  • 只需要给共享数据添加一个关键字即可
public class PrintString {
    volatile private boolean flag = true;
    public void setFlag(boolean flag) {
        this.flag = flag;
    }
    public void printString() {
        while (flag) {
            System.out.println("打印字符串");
        }
    }

}