重拾java基础(十八):多线程下总结

一、死锁

1、同步锁可以解决线程安全问题,但是同步锁会带来死锁问题;
2、死锁就是彼此占用对方的资源,使程序暂停,无法继续运行下去。
3、死锁出现的概率 非常小 但是危害非常大。
4、案例: 奥巴马和普京一起吃饭,饭菜都上齐了,非常美味,他们非常饿,
         开吃吧...但是每个人手里只有一根筷子...如果没有人愿意共享自
         己的筷子,那么他们就只能饿着...看着...馋着...留着口水...
a. 奥巴马是一个线程   奥巴马要吃饭,要普京的筷子
b. 普京是一个线程   普京要吃饭,要奥巴马的筷子
c. 嵌套锁 + 交叉锁

这里写图片描述
这里写图片描述
这里写图片描述

注意:线程之间彼此占用对方所需的资源,就是死锁

二、线程间的通信

1、在实现线程安全时,程序进入同步代码块后就会自动上锁,直到程序把代码块中的代码执行完后才会进行下步操作。

2、每个对象都有一把锁,那么开锁的方法就被定义到了Object类中;
    Public final void wait(),让当前线程等待,同时释放锁,直到被再次唤醒。

    public final void wait(long timeout),在指定时间内让当前线程等待,同时释放锁,

     wait()和sleep()都可以让当前线程等待,区别:

            1,sleep():释放执行权(等待),不释放锁

           2,wait():释放执行权(等待),同时释放锁

如果调用的是无参的wait()方法,那锁就一直释放,当前线程一直等待,还需要唤醒。Object类提供了notify()方法用来唤醒某个被wait()的锁,也就是唤醒线程

细节:
wait()和notify()方法都是操作锁的,而锁存在于同步中,也就是说这两个方法必须出现在同步中(同步代码块或同步方法)。
同步锁不仅可以解决昨天的线程安全问题,还可以实现线程间的通信

3、线程间的通信
    例子:一个线程输出10次1,一个线程输出10次2,观察执行结果
           现要求交替输出“1 2 1 2 1 2...” 或 “2 1 2 1 2 1...
public class Testnotif1 extends Thread{
    public void run(){
        for (int i = 0; i < 10; i++) {
            synchronized (MyLocd.o1) {
                System.out.println(1);
                MyLocd.o1.notify();
                try {
                    MyLocd.o1.wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}
package cn.itcast.Thread;

public class Testnotif2 extends Thread {
    public void run() {
        for (int i = 0; i < 10; i++) {
            synchronized (MyLocd.o1) {
                System.out.println(2);
                MyLocd.o1.notify();
                try {
                    MyLocd.o1.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        }
    }
}
package cn.itcast.Thread;

public class Testnotif {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Testnotif1 f1=new Testnotif1();
        Testnotif2 f2=new Testnotif2();
        f1.start();
        f2.start();
    }

}
线程之间是互相独立,这个通信指的是线程之间互相打个招呼,控制CPU
  的随机性
notify()方法     叫醒正在休息的线程     Object类
该方法只能叫醒跟他共用一把锁(这把锁类似于中间人)的那个线程
  • 生成消费者模式
1. 线程间通信     经典案例

2. 分析
   a. 农夫是一个线程,不停的往框里放水果     生产者
   b. 小孩是一个线程,不停的从框里吃水果    消费者
   c. 是要用死循环的
   d. 可以用sleep()来模拟控制生产速度和消费速度
   e. 框满了,让农夫停
   f. 框里没水果了,让小孩停
   g. 互相唤醒
代码演示:


public class MyLocd {
    public static Object o1=new Object();
    public static Object o2=new Object();
}
package cn.itcast.Thread;

public class TestHaizi extends Thread{
    public void run(){
        while(true){
            synchronized (Kuang.al) {
                if (Kuang.al.size() <= 0) {
                    try {
                        Kuang.al.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                Kuang.al.remove(0);
                Kuang.al.notify();
                System.out.println("孩子吃了一个,框里还有" + Kuang.al.size() + "个水果!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}
package cn.itcast.Thread;

public class Testnongfu extends Thread{
    public void run(){
        while(true){
            synchronized (Kuang.al) {
                if (Kuang.al.size() >= 30) {
                    try {
                        Kuang.al.wait();
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
                Kuang.al.add(1);
                Kuang.al.notify();
                System.out.println("农夫在框里放了一个,框里总共" + Kuang.al.size() + "个水果!");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }
}
package cn.itcast.Thread;

public class TestNongfuHaozi {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Testnongfu t1=new Testnongfu();
        TestHaizi  t2=new TestHaizi();
        t1.start();
        t2.start();
    }

}

三、线程状态
这里写图片描述

四、单例设计模式

*********************只能创建出来一个对象***************************
   //懒汉式
class Single{
    private static Single s = null;
    private Single(){}
    public  synchronized  static Single getInstance(){
        if (s == null){
               s = new Single();
        }
        return s;
    }
}         //面试时懒汉式出现的几率非常大
//饿汉式
public class Singleton{
            private static Singleton s = new Singleton ();
            private Singleton (){}
            public static Singleton getInstance(){
                   return s;
            }
 } 

懒汉式存在线程安全问题,虽然能解决,但是会造成效率变低,因此开发的时候建议使用饿汉式实现单例设计模式
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值