Java基础学习生疏知识点总结(19)——多线程(下)

2021/4/23 1:55:08

本文主要是介绍Java基础学习生疏知识点总结(19)——多线程(下),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

文章目录

  • 1、线程生命周期
  • 2、多线程的实现方式二:Runnable
  • 3、继承Thread(方式一)和实现Runnable接口(方式二)比较
  • 4、数据安全问题

1、线程生命周期

五种线程状态

新建:线程对象刚刚创建出来 没有start

就绪:执行start方法 启动了 没有CPU的执行权

执行:抢到了CPU的执行权 该线程在CPU上运行

阻塞:没有CPU的执行权 还缺少一些必要条件

死亡:线程中的run方法执行完,被当做垃圾被垃圾回收机制回收

各个状态之间的转换
在这里插入图片描述

2、多线程的实现方式二:Runnable

在这里插入图片描述
步骤

1.实现Runnable接口

2.重写run方法

3.创建Runnable子类对象

4.创建Thread对象,并且把刚创建的Runnable子类对象作为参数传递

5.start方法启动

public class Demo {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        // thread 对象才代表线程
        Thread thread = new Thread(myRunnable);

        thread.setName("宋仲基");

        thread.start();
    }
}

class MyRunnable implements Runnable {

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {

            System.out.println(Thread.currentThread().getName()
            +"---"+i);
        }
    }
}

注意事项

  • 我们Runnable接口子类的run()方法代码,会运行在子线程当中。

  • 所以,在线程的第二种实现方式中,我们自己定义子类,实现Runnable接口的run方法,将要在子线程中执行

  • 但是,Runnable子类对象,并不代表线程,它只代表,要在线程中执行的任务。

    我们认为,从逻辑上说,第二种方法逻辑十分清晰:

  • 线程就是一条执行路径,至于在线程这条执行路径上,究竟执行的是什么样的具体代码, 应该和线程本身没有关系的

  • 也就是说,线程,和在线程(执行路径)上执行的任务应该是没有什么直接关系的

  • 线程实现的第二种方式,把线程(Thread对象代表线程) 和在 线程上执行的任务(Ruannable子类对象)分开

// 为什么Runnable当中的run方法会运行在子线程当中
new Thread(Runnable target)

Thread{
private Runnable target;
init(xxx){
	this.target = target;
}
run (){
	if(target!=null){
		target.run();
	}
}
}

3、继承Thread(方式一)和实现Runnable接口(方式二)比较

方式二一 VS 方式二:

  • 方式一实现步骤较方式二少
  • 方式一的实现方式,存在单重继承的局限性
  • 方式二将线程和任务解耦
  • 方式二,便于多线程数据的共享

4、数据安全问题

练习:

多线程仿真如下场景:
假设A电影院正在上映某电影,该电影有100张电影票可供出售,现在假设有3个窗口售票。请设计程序模拟窗口售票的场景。

分析:
3个窗口售票,互不影响,同时进行。
3个窗口共同出售这100张电影票

结果:

  • 产生了重复的票
  • 产生了不存在的票

方式一:

public class Demo3 {
    public static void main(String[] args) {
        SellWindow sellWindow = new SellWindow();
        SellWindow sellWindow2 = new SellWindow();
        SellWindow sellWindow3 = new SellWindow();

        sellWindow.setName("A窗口");
        sellWindow2.setName("B窗口");
        sellWindow3.setName("C窗口");

        sellWindow.start();
        sellWindow2.start();
        sellWindow3.start();
    }
}

class SellWindow extends Thread {
    static int tickets = 100;
    @Override
    public void run() {
        while (true) {
            if (tickets > 0) {
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(getName()+"卖了第"+tickets--+"票");
            }
        }
    }
}

方式二:

public class Demo4 {
    public static void main(String[] args) {
        SellWindow2 sellWindow2 = new SellWindow2();

        Thread thread = new Thread(sellWindow2);
        Thread thread2 = new Thread(sellWindow2);
        Thread thread3 = new Thread(sellWindow2);

        thread.setName("窗口A");
        thread2.setName("窗口B");
        thread3.setName("窗口C");

        thread.start();
        thread2.start();
        thread3.start();

    }
}

class SellWindow2 implements Runnable {
    int tickets = 100;
    @Override
    public void run() {
        while (true) {
            // 假设是线程A抢到CPU的执行权 tickets=100
            // 线程B抢到了CPU的执行权  100
            
            // 不存在的原因 假设A执行 此时 tickets=1
            if (tickets > 0) {
                try {
                    // 线程A睡眠 B睡眠
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()
                +"卖了第"+tickets-- + "票");
                // A走到这里  100 
                // 又发生了线程切换 B抢到了CPU的执行权 100
                // A输出 卖了第100 张票
                // B输出 卖了第100 张票
                
                // tickets--拆成3步
                // 1.取值  2.做-1操作  3.重写赋值
                
                
                // ABC三个线程都进入了if
                // 最坏情况
                // A 卖了第1张票 此时还剩0张
                // B 卖了第0张票 此时还剩-1张票
                // C 卖了第-1张票 此时还剩-2张票
            }
        }
    }
}

在这里插入图片描述



这篇关于Java基础学习生疏知识点总结(19)——多线程(下)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程