JavaThread 03 Runnable&&初识并发问题

1.4 Runnable&&初识并发问题


1.4.1 实现 Runnable 接口

其实 Thread 这个类 就是 Runnable 接口的 实现,所以我们 建议 直接 用 Runnable 接口,而不是 去用 二次封装的 Thread 是有道理的。

需要注意的是,Runnable 接口 在 开启线程之前,需要 建立 一个 Thread 对象,作为 代理,用来 开启 线程!

package www.muquanyu.lesson01;

public class RunnableDemo implements Runnable {

    @Override
    public void run() {
        for(int i = 0;i<200;++i)
        {
            System.out.println("线程:" + i);
        }
    }

    public static void main(String[] args) {

//需要 建立一个 Thread 对象
        Thread thread = new Thread(new RunnableDemo());
        thread.start();

        for(int i = 0;i<200;++i)
        {
            System.out.println(i);
        }
    }

}

在这里插入图片描述

  • 两者的区别
  1. 继承 Thread 类
  • 子类继承 Thread 类 具备 多线程能力
  • 启动线程:子类对象.start()
  • 不建议使用:避免OOP 单继承的局限性
  1. 实现 Runnable 接口
  • 实现接口 Runnable 具有多线程能力
  • 启动线程:传入目标对象 + Thread 对象.start()
  • 推荐使用:避免单继承的局限性,灵活方便,方便同一个对象被多个线程使用

    比如说 三个线程 同时 跑 一个 事务!如果你继承 Thread 是无法实现的。只有 实现 Runnable 接口 才可以。

1.4.2 初识并发问题

比如我们 三个人 去 抢 十张票,那么 这三个 人 就相当于 三个线程,并且 在做同一个事情,那就是 抢票。也就相当于 在处理 同一个事务下的 资源。这种情况,就会 出现 “并发” 问题。

package www.muquanyu.lesson01;

import sun.misc.PostVMInitHook;

public class 多线程同时处理一个事务 implements Runnable {

    //票数
    private int ticketNums = 10;

    @Override
    public void run() {
        while (true)
        {
            if(ticketNums <= 0)
            {
                break;
            }
            //模拟延迟
            try {
                Thread.sleep(200);
            }catch (Exception e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticketNums--+"票");
        }

    }

    public static void main(String[] args) {
        多线程同时处理一个事务 test = new 多线程同时处理一个事务();

        new Thread(test,"小明").start();
        new Thread(test,"老师").start();
        new Thread(test,"黄牛党").start();
    }
}

我们可以 清晰地 看到 我们 开了 三个 线程,在 处理 一个 事务。分别是 小明、老师、黄牛党,在 同一个事务里面,抢去 资源(票)。但是 票数 是有限的,所以 肯定会 出现 乱抢的情况。因为数据量 过小,我们 就加上了 sleep 延迟,这样就会 更加可观的看到 结果。在这里插入图片描述

这个时候,我们发现 可能会有人 抢到 -1 这个票,也可能会有人 抢到 的票 是 同一个。这就叫 并发问题。

当多个 线程对象,操作同一个 资源的情况下,线程是不安全的。最明显的 现象 就是 数据紊乱。。。


1.4.3 并发问题(龟兔赛跑)

我们还有一个 典型的并发问题。————> 龟兔赛跑-Race
乌龟和兔子同时都在一条跑道上赛跑,肯定要争先抢后的去跑每一步,道路上的地方就那么大。但是他俩 确实 就有 其中 一个 可能会 后抢到 道路的那块资源,或 先抢到 道路上的那块资源,导致最后 谁赢(谁先抢到 资源,或抢的多,肯定就赢了。)

  1. 首先来个赛道距离,然后要离终点越来越近。(可以设定跑了多少米)
  2. 判断比赛是否结束(距离为 0 不就结束了吗)
  3. 打印出 胜利者
  4. 龟兔赛跑开始
  5. 故事中乌龟赢了,兔子是在睡觉的,所以我们来模拟 一下 兔子睡觉就行了。
  6. 终于,乌龟赢得了 比赛。

在这里插入图片描述

package www.muquanyu.lesson01;

//模拟龟兔赛跑
public class Race implements Runnable {
    //只能 有一个 胜利者,所以是 静态的
    private static String winner;
    @Override
    public void run() {

        for(int i = 0;i <= 100;++i)
        {
            if(Thread.currentThread().getName().equals("兔子") && i%10==0)
            {
                try{
                    Thread.sleep(1);
                }catch (InterruptedException e)
                {
                    e.printStackTrace();
                }
            }
            boolean flag = gameOver(i);
            if(flag)
            {
                break;
            }
            System.out.println(Thread.currentThread().getName() + "-->跑了"+i+"米!");
        }
    }

    private boolean gameOvera(int i) {
        return false;
    }

    //判断是否完成比赛
    private boolean gameOver(int steps)
    {
        if(winner != null)
        {
            return true;
        }
        if(steps == 100)
        {
            winner = Thread.currentThread().getName();
            System.out.println("winner is "+ winner);
            return true;
        }
        return false;
    }


    public static void main(String[] args) {
        Race race = new Race();

        Thread 兔子 = new Thread(race, "兔子");
        Thread 乌龟 = new Thread(race, "乌龟");
        兔子.start();
        乌龟.start();
    }
}

在这里插入图片描述

在模拟这个 过程的时候,我们 让 兔子 在 10米的地方 睡觉了,但是 你发现,兔子 还没等睡觉呢,乌龟可能就跑到了。这是因为 当代 CPU 处理的 太快了,它会 自动的 帮你调度。这也是为什么 我们当初 说 这个 所谓的 调度 是你控制不了的,CPU 和 系统 让你怎么来 你就得 怎么来(当然 人家都是 往 最优的 策略上 去 调度的)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值