(4)Java多线程之安全问题-下

来源:互联网 发布:suse12 linux 网卡配置 编辑:程序博客网 时间:2024/05/24 05:36

  • 引言
  • 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

这里写图片描述

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("打印字符串");        }    }}
1 0
原创粉丝点击