黑马程序员_日记16_Java多线程(六)

 ——- android培训java培训、期待与您交流! ———-

死锁

一、基本概念

死锁是什么呢?

两个线程分别持有一个资源,

并同时请求得到对方的资源。

在这种情况下产生的不正常情况就叫做死锁。

死锁在什么情况下会发生呢?

死锁在同步嵌套同步的情况下会发生。

至少有2把锁,才会产生死锁。

二、死锁实例1

首先,以前面售票的例子展示一下死锁。

class Ticket implements Runnable
{
    private  int tick = 1000;
    Object obj = new Object();
    boolean flag = true;
    public  void run()
    {
        if(flag)
        {
            while(true)
            {
                synchronized(obj)
                {
                    show();
                }
            }
        }
        else
            while(true)
                show();
    }
    public synchronized void show()//this
    {
        synchronized(obj)
        {
            if(tick>0)
            {
                try{Thread.sleep(10);}catch(Exception e){}
                System.out.println(Thread.currentThread().getName()+"....code : "+ tick--);
            }
        }
    }
}

class  DeadLockDemo
{
    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;
        t2.start();

    }
}

运行结果见下图

如图所示,票额为1000张,但是卖到984的时候就卡主动不了了,

说明发生了死锁。

三、死锁实例2

下面我自己写了一个简答的例子,来测试死锁。

//建立一个锁类,注意:锁就是对象,在这里使用Object类的对象
class MyLock
{
    //建立两把锁,注意为了调用方便,使用static修饰
    static Object locka = new Object();
    static Object lockb = new Object();
}

//建立一个会产生死锁的类
class MyDeadLock implements Runnable
{
    //设置一个标识来让两个线程各自执行一部分代码
    private boolean flag;

    //利用构造函数传递标识
    MyDeadLock(boolean flag)
    {
        this.flag = flag;
    }
        //覆盖run方法
        public void run()
        {
                //如果标识为true,则该线程执行if部分代码
                if(flag==true)
                {
                    //让程序一直转,直到死锁
                    while(true)
                    {
                            //利用同步代码块嵌套同步代码快制造死锁
                            //因为static修饰了锁,所以可以直接用类名.锁,直接调用对象
                            synchronized(MyLock.locka)
                            {
                                //表示线程在if语句中拿到了locka锁
                                System.out.println("线程:"+Thread.currentThread().getName()+"在if中拿到了 locka.锁......");
                                synchronized(MyLock.lockb)
                                {
                                    //表示线程在if语句拿到了lockb锁
                                    System.out.println("线程:"+Thread.currentThread().getName()+"在if中拿到了 lockb锁......");
                                }
                            }
                    }
                }
                //否则执行else的这部分代码
                else
                {
                    //让程序一直转,直到死锁
                    while(true)
                    {
                            //利用同步代码块嵌套同步代码快制造死锁
                            synchronized(MyLock.lockb)
                                {
                                    //表示线程在else语句中拿到了lockb锁
                                    System.out.println("线程:"+Thread.currentThread().getName()+"在else中拿到了lockb锁.....");
                                    synchronized(MyLock.locka)
                                    {
                                        //表示线程在else语句拿到了locka锁
                                        System.out.println("线程:"+Thread.currentThread().getName()+"在else中拿到了lockb锁.....");
                                    }
                                }
                    }
                }
        }

}

class MyDeadLockDemo
{
    public static void main(String[] args)
    {
        //通过线程类建立线程对象,并将实现了接口Runnable类的对象作为实际参数传递进去
        Thread t1 = new Thread(new MyDeadLock(true));
        Thread t2 = new Thread(new MyDeadLock(false));

        //调用start方法,启动线程1
        t1.start();

        //为了让程序多运行一会儿再死锁
        try{Thread.sleep(10);}catch(Exception e){}

        //调用start方法,启动线程1
        t2.start();
    }
}

运行结果

线程:Thread-0在if中拿到了 locka.锁……

线程:Thread-0在if中拿到了 lockb锁……

线程:Thread-0在if中拿到了 locka.锁……

线程:Thread-0在if中拿到了 lockb锁……

线程:Thread-0在if中拿到了 locka.锁……

线程:Thread-0在if中拿到了 lockb锁……

线程:Thread-0在if中拿到了 locka.锁……

线程:Thread-0在if中拿到了 lockb锁……

线程:Thread-0在if中拿到了 locka.锁……

线程:Thread-1在else中拿到了lockb锁…..

结果显示:当线程Thread-1刚跑起来,就立刻造成了死锁

四、小结

在了解了死锁的原理之后,以后下程序的时候就一定注意

避免死锁的发生,这样才能保证程序的安全性。

时间: 2024-10-11 06:48:42

黑马程序员_日记16_Java多线程(六)的相关文章

黑马程序员_日记19_Java多线程(九)

--- android培训.java培训.期待与您交流! ---- 1 停止线程 原理:让run方法结束.而run方法中通常定义循环结构,所以就是控制住循环结构就可以了. stop方法已经过时了. 如何控制循环结构?? 1 定义结束标记 2 当线程处于了冻结状态,没有执行标记,程序一样无法结束. 这时可以循环,正常退出冻结状态,或者强制结束冻结状态. 强制结束冻结状态:interrupt();目的是线程强制从冻结状态恢复到运行状态. 但是会发生InterruptedException异常. //

黑马程序员_日记17_Java多线程(七)

--- android培训.java培训.期待与您交流! ---- 线程间通信 线程间的通信: 其实就是多个线程操作同一个资源,但是操作的动作不同. 一.我的示例 这是我写的关于线程间通信的示例. 本示例需要定义三个类: 1 资源类Resource 2 输入类Input 3 输出类Output 步骤: 1 先写出基本代码 2 找安全问题并修改 1 初级代码 //本类定义的资源是,人的数据 class Resource { private String name;//私有化人的名字 private

黑马程序员_日记18_Java多线程(八)--生产者消费者问题JDK1.5特性

--- android培训.java培训.期待与您交流! ---- 生产者消费者问题JDK1.5特性 一.概述 在JDK1.5之前,解决生产者和消费者问题, 用的是synchronized同步+while+notify(): 但是这种方法很不安全,很容易让线程全部陷入无限等待状态. 于是我们改用notiyfyAll();来解决. 这样虽然解决了安全问题,但还是存在不足和安全隐患. notifyAll方法唤醒了线程池中全部的线程, 这并不是我们想要的! 而且,同步套同步很容易发生死锁! 在JDK1

黑马程序员-学习日记(多线程的初步认识)

 ------Java EE培训.Android培训.iOS培训.期待与您交流! ------- 进程:正在执行的应用程序.一个应用程序运行时内存分配的空间.线程:进程中一个程序执行的控制单元,一条执行路径.负责程序的执行顺序.多线程:在java虚拟机启动的时候会有一个java.exe的执行程序,即一个进程.该进程中至少有一个线程负责java程序的运行.而且这个线程运行的代码存在于main方法中. class Demo extends Thread { public void run() { f

黑马程序员-学习日记(多线程)

进程:正在执行的应用程序.一个应用程序运行时内存分配的空间.线程:进程中一个程序执行的控制单元,一条执行路径.负责程序的执行顺序. 多线程存在的意义: 程序运行中至少有两个线程在运行,一个是主函数的主线程,另一个是垃圾回收的线程. 线程创建方式一: 继承Thread类.要覆盖其run方法,调用线程的start方法. 作用:1.启动线程 2.运行run方法.目的是将自定义的代码存储在run方法中,让线程运行 cpu每次只执行一个程序,只是在快速的不同线程间切换,表现了多线程的随机性 class M

黑马程序员-学习日记(多线程安全问题和死锁认识)

------Java培训.Android培训.iOS培训.期待与您交流! ------- 安全问题产生的原因: 当多条代码语句在操作同一个共享数据时,一个线程对多条语句只执行了一部分,还没有执行完, 另一个线程参与进来执行.导致共享数据的错误. class Mlpc implements Runnable { private int ticket = 50; public void run() { while(true) { if(ticket>0) { try { Thread.sleep(2

黑马程序员_日记24_字符串获取计数练习

--- android培训.java培训.期待与您交流! ---- /* 获取一个字符串在另一个字符串中出现的次数. 例如:"kk"在"abkkcdkkefkkskk"中出现的次数 分析功能: 1 功能的结果:返回字符串1在字符串2中出现的次数------------返回值类型为int 2 有没有未知变量:有两个.第一,字符串1:第二,字符串2.--参数类型(String str1,String str2) 如何实现功能:"kk"在"a

黑马程序员-学习日记(多线程间的通信)

 ------Java EE培训.Android培训.iOS培训.期待与您交流! ------- 示例: //将资源封装成对象 class Resour { String name; String gender; } //将线程执行的任务封装成对象 class Input implements Runnable { private Resour r; Input(Resour r) { this.r = r; } public void run() { int x =0; while(true)

黑马程序员-学习日记(多线程的安全)

安全产生的原因: 当多条语句在操作同一个共享数据时,一个线程对多条语句只执行了一部分,还没有执行完, 另一个线程参与进来执行.导致共享数据的错误. class Mlpc implements Runnable { private int ticket = 50; public void run() { while(true) { if(ticket>0) { try { Thread.sleep(20); //让线程进入冻结状态 } catch (Exception e) { } System.