Javase进阶1:多线程

目录

0.学习目标

1. 笔记

2. 练习


0.学习目标

1、整理多线程题目
(1)wait和sleep区别
(2)线程的状态有哪些
(3)在同步代码块或者同步方法中,什么情况下会释放锁


2、编写多线程代码
/**
 * 创建两个线程
 * 创建一个初始 变量 值 包子状态为false
 * 实现一个线程吃包子,另外一个线程做包子
 * 交替,进行10次
 */


3、编写泛型方法,实现两个数相加,限定参数只能是数字

1. 笔记

1、线程间通信
(1)创建线程因为操作系统进行调度的,创建顺序不确定的,在程序通过条件控制,让线程执行有
顺序的,这个个过程--等待唤醒(通知)机制

(2)等待唤醒(通知)机制调用方法
第一个 wait() : 释放锁,需要被唤醒
第二个 notify()/notifyAll():通知其他线程
* 上面三个方法都是Object类里面的方法

(3)编写线程间通信例子
/**
 * 创建两个线程
 * 创建一个初始 变量 值是0
 * 实现一个线程对变量+1 ,另外一个线程对变量-1
 * 交替,进行10次
 */

2、线程其他概念
  (1)线程生命周期
  - 线程的生命周期有五种状态:新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)、死亡(Dead)。

  (2)线程阻塞:
 - 线程调用了sleep()方法,主动放弃所占用的CPU资源;
 - 线程试图获取一个同步监视器,但该同步监视器正被其他线程持有;
 - 线程执行过程中,同步监视器调用了wait(),让它等待某个通知(notify);
 - 线程执行过程中,同步监视器调用了wait(time)
 - 线程执行过程中,遇到了其他线程对象的加塞(join);

     public enum State {
        NEW,   新建
        RUNNABLE,  准备就绪
        BLOCKED,   阻塞
        WAITING,   不见不散
        TIMED_WAITING, 过时不候
        TERMINATED;    终结
    }

(3)Thread和Runnable区别
    1. 适合多个相同的程序代码的线程去共享同一个资源。
    2. 可以避免java中的单继承的局限性。
    3. 增加程序的健壮性,实现解耦操作,代码可以被多个线程共享,代码和线程独立。
    4. 线程池只能放入实现Runable或Callable类线程,不能直接放入继承Thread的类。

(4)释放锁操作
* 当前线程的同步方法、同步代码块执行结束。
* 当前线程在同步代码块、同步方法中遇到break、return终止该代码块、该方法的继续执行。
* 当前线程在同步代码块、同步方法中出现未处理的Error或Exception,导致当前线程异常结束。
* 当前线程在同步代码块、同步方法中执行了锁对象的wait()方法,当前线程被挂起,并释放锁。

(5)死锁
    不同的线程分别锁住对方需要的同步监视器对象不释放,都在等待对方先放弃时就形成了线程的死锁。
    一旦出现死锁,整个程序既不会发生异常,也不会给出任何提示,只是所有线程处于阻塞状态,无法继续。

(6)sleep()和wait()方法的区别
   - sleep()不释放锁,wait()释放锁
   - sleep()自动在指定时间唤醒,wait()可以指定时间可以使用notify或notifyAll唤醒
   - sleep()在Thread类中声明的静态方法,wait方法在Object类中声明

2. 练习

练习一:比较接口创建线程(分开)和匿名内部类创建线程区别(合并)

接口创建线程

public class ThreadDemo2 {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
      Thread Thread = new Thread(myRunnable,"接口创建线程");
        Thread.start();
    }

}

//实现Runnable接口创建线程
class MyRunnable implements Runnable{
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());

    }
}

匿名内部类创建线程

public class ThreadDemo3 {
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        }, "匿名内部类创建线程").start();
    }
}

练习二:

/**
 * 创建两个线程
 * 创建一个初始 变量 值是0
 * 实现一个线程对变量+1 ,另外一个线程对变量-1
 * 交替,进行10次
 */
public class ThreadDemo1 {

    public static void main(String[] args) {
        OneAddDiv oneAddDiv = new OneAddDiv();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <=10; i++) {
                    //+1
                    try {
                        oneAddDiv.addOne();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        },"AA").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <=10; i++) {
                    //+1
                    try {
                        oneAddDiv.divOne();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        },"BB").start();
    }
}

//第一步 创建资源类,定义属性和操作方法
class OneAddDiv {
    //定义变量 0
    private int number = 0;

    //定义操作方法
    // +1方法
    public synchronized void addOne() throws InterruptedException {
        //如果number不是0,等待
        if(number !=0) {  // 不等于0 就是1
            //等待
            this.wait();
        }
        //如果number是0,进行+1操作
        number++;

        System.out.println(Thread.currentThread().getName()+" "+number);
        //通知其他线程
        this.notifyAll();
    }

    //-1方法
    public synchronized void divOne() throws InterruptedException {
        if(number != 1) {
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName()+" "+number);
        this.notifyAll();
    }
}

练习三:一对一做包子吃包子问题

解释:包子铺线程生产包子,吃货线程消费包子。当包子没有时(包子状态为false),吃货线程等待,包子铺线程生产包子(即包子状态为true),并通知吃货线程(解除吃货的等待状态),因为已经有包子了,那么包子铺线程进入等待状态。接下来,吃货线程能否进一步执行则取决于锁的获取情况。如果吃货获取到锁,那么就执行吃包子动作,包子吃完(包子状态为false),并通知包子铺线程(解除包子铺的等待状态),吃货线程进入等待。包子铺线程能否进一步执行则取决于锁的获取情况。

包子资源类

public class BaoZi {
     String  pier ;
     String  xianer ;
     boolean  flag = false ;//包子资源 是否准备好  包子资源状态
}

 吃货线程类

public class ChiHuo extends Thread{
    private BaoZi bz;

    public ChiHuo(String name,BaoZi bz){
        super(name);
        this.bz = bz;
    }
    @Override
    public void run() {
        while(true){
            synchronized (bz){
                if(bz.flag == false){//没包子
                    try {
                        bz.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }                
                
                System.out.println("吃货正在吃:"+bz.pier+","+bz.xianer+"包子");
                bz.flag = false;
                bz.notify();
            }
        }
    }
}

包子铺线程类

public class BaoZiPu extends Thread {

    private BaoZi bz;

    public BaoZiPu(String name,BaoZi bz){
        super(name);
        this.bz = bz;
    }

    @Override
    public void run() {
        int count = 0;
        //造包子
        while(true){
            //同步
            synchronized (bz){
                if(bz.flag == true){//包子资源  存在
                    try {
                        bz.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                // 没有包子  造包子
                System.out.println("包子铺开始做包子");
                if(count%2 == 0){
                    // 薄皮  蟹黄包
                    bz.pier = "薄皮";
                    bz.xianer = "蟹黄灌汤";
                }else{
                    // 厚皮  牛肉大葱
                    bz.pier = "厚皮";
                    bz.xianer = "牛肉大葱";
                }
                count++;

                bz.flag=true;
                System.out.println("包子造好了:"+bz.pier+bz.xianer);
                System.out.println("吃货来吃吧");
                //唤醒等待线程 (吃货)
                bz.notify();
            }
        }
    }
}

测试类

public class Demo {
    public static void main(String[] args) {
        //等待唤醒案例
        BaoZi bz = new BaoZi();

        ChiHuo ch = new ChiHuo("吃货",bz);
        BaoZiPu bzp = new BaoZiPu("包子铺",bz);

        ch.start();
        bzp.start();
    }
}

执行效果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

疯丰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值