初学多线程

多线程–Thread类

多线程的创建

1.继承Thread类

2.实现Runnable接口

3.实现Callable接口(了解)

举例

学习B站韩顺平老师,主要的理解通过继承Thread类来实现多线程的创建:

//演示通过继承 Thread类创建线程
public class Thread01 {
    public static void main(String[] args) {
        //创建Cat对象,可以当作线程使用
        Cat cat = new Cat();
        cat.start();//启动线程
        //cat.run() ;
        // run方法就是一个普通的方法,没有真正的启动一个线程,就会把run方法执行完毕,才向下执行
        // 说明:当main线程启动一个子线程Thread-0,主线程不会阻塞,会继续执行
        //这时主线程和子线程是交替执行..
        System.out.println("主线程继续执行" + Thread.currentThread().getName());//名字main
        for (int i = 0; i < 60; i++) {
            System.out.println("主线程i=" + i);//让主线程休眠
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (i == 5) {
                break;
            }

        }
    }
}

    //当一个类继承了Thread类,该类就可以当作一个线程使用了
//我们会重写run方法,写上自己的业务代码
//run方法,Thread类实现了Runable接口的run方法
//@Override
//public void run() {
//    if (target != null) {
//        target.run();
//    }
//}

        class Cat extends Thread {
            int times = 0;

            @Override
            public void run() {//重写run方法,写上自己的业务逻辑
                while (true) {

                    //该线程每隔1秒。在控制台输出“瞄瞄,我是小猫咪"
                    System.out.println("喵喵,我是小猫咪" + (++times));
                    //让该线程休眠一秒
                    try {
                        Thread.sleep(1000);//ctrl+alt+T
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if (times == 8) {
                        break;//当times 到5,退出while,这时线程也就退出..

                    }
                }
            }
        }


通过实现Runnable接口来创建多线程

package com.hspedu.threaduse;
//通过实现接口Runnable来开发线程
public class Thread02 {
    public static void main(String[] args) {
        Dog dog = new Dog();
//        dog.start();这里不能调用start
        new Thread(dog).start();
    }
}
class Dog implements Runnable{//通过实现Runnable接口,开发线程
int count =0;
    @Override
    public void run() {
        while (true) {
            System.out.println("小狗汪汪叫,hi"+(++count)+Thread.currentThread().getName());

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (count==10){
                break;
            }
        }

    }
}

实际应用

用以上两种方式模拟三个售票窗口售卖100张票的多线程案例

package com.hspedu.ticket;
//使用多线程模拟三个窗口同时售票100张
public class SellTicket {
    public static void main(String[] args) {
//        SellTicket01 sellTicket01 = new SellTicket01();
//        SellTicket01 sellTicket02 = new SellTicket01();
//        SellTicket01 sellTicket03 = new SellTicket01();
        //出现问题:票数超卖
//

        //SellTicket02:
        System.out.println("使用实现接口的方式来售票===================================================================");
        //同样出现超卖现象
        //以后学习Synchronized来解决
        SellTicket02 sellTicket02 = new SellTicket02();
        new Thread(sellTicket02).start();//第一个线程窗口
        new Thread(sellTicket02).start();//第二个线程窗口
        new Thread(sellTicket02).start();//第三个线程窗口
    }
}
//使用继承Thread方式
class SellTicket01 extends Thread{

    public static int ticketNum=100;//让多个线程共享票数
    @Override
    public void run() {
        while (true) {

            if (ticketNum <= 0) {
                System.out.println("卖完啦");
                break;
            }
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("窗口" + Thread.currentThread().getName() + "售出一张票" + "剩余票数" + (--ticketNum));
            }
        }
    }
//实现接口
class SellTicket02 implements Runnable{
    public int ticketNum=100;//让多个线程共享票数
    @Override
    public void run() {
        while (true) {

            if (ticketNum <= 0) {
                System.out.println("卖完啦");
                break;
            }
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("窗口" + Thread.currentThread().getName() + "售出一张票" + "剩余票数" + (--ticketNum));
        }
    }
}

总结:两种方式相差不大,无论用哪一种方式来实现这个售票案例,都会出现一个缺陷,我们可以运行一下这个程序,发现两种方法结果都有可能出现多售出,(超出一百张票),运行结果如下:

连接到目标VM, 地址: ''127.0.0.1:59981',传输: '套接字'', 传输: '{1}'
使用实现接口的方式来售票===================================================================
窗口Thread-0售出一张票剩余票数99
窗口Thread-1售出一张票剩余票数99
窗口Thread-2售出一张票剩余票数99
窗口Thread-2售出一张票剩余票数98
窗口Thread-0售出一张票剩余票数97
窗口Thread-1售出一张票剩余票数96
窗口Thread-2售出一张票剩余票数95
窗口Thread-0售出一张票剩余票数94
窗口Thread-1售出一张票剩余票数95
窗口Thread-1售出一张票剩余票数92
窗口Thread-2售出一张票剩余票数93
窗口Thread-0售出一张票剩余票数91
窗口Thread-1售出一张票剩余票数90
窗口Thread-2售出一张票剩余票数90
窗口Thread-0售出一张票剩余票数90
窗口Thread-2售出一张票剩余票数89
窗口Thread-1售出一张票剩余票数89
窗口Thread-0售出一张票剩余票数89
窗口Thread-1售出一张票剩余票数88
窗口Thread-0售出一张票剩余票数88
窗口Thread-2售出一张票剩余票数88
窗口Thread-2售出一张票剩余票数87
窗口Thread-1售出一张票剩余票数87
窗口Thread-0售出一张票剩余票数87
窗口Thread-1售出一张票剩余票数86
窗口Thread-2售出一张票剩余票数86
窗口Thread-0售出一张票剩余票数86
窗口Thread-1售出一张票剩余票数84
窗口Thread-0售出一张票剩余票数83
窗口Thread-2售出一张票剩余票数85
窗口Thread-0售出一张票剩余票数82
窗口Thread-2售出一张票剩余票数82
窗口Thread-1售出一张票剩余票数81
窗口Thread-1售出一张票剩余票数80
窗口Thread-0售出一张票剩余票数79
窗口Thread-2售出一张票剩余票数78
窗口Thread-2售出一张票剩余票数77
窗口Thread-0售出一张票剩余票数77
窗口Thread-1售出一张票剩余票数77
窗口Thread-1售出一张票剩余票数76
窗口Thread-0售出一张票剩余票数75
窗口Thread-2售出一张票剩余票数76
窗口Thread-1售出一张票剩余票数74
窗口Thread-0售出一张票剩余票数73
窗口Thread-2售出一张票剩余票数74
窗口Thread-1售出一张票剩余票数71
窗口Thread-2售出一张票剩余票数70
窗口Thread-0售出一张票剩余票数72
窗口Thread-2售出一张票剩余票数69
窗口Thread-1售出一张票剩余票数68
窗口Thread-0售出一张票剩余票数67
窗口Thread-0售出一张票剩余票数65
窗口Thread-2售出一张票剩余票数66
窗口Thread-1售出一张票剩余票数65
窗口Thread-1售出一张票剩余票数64
窗口Thread-2售出一张票剩余票数63
窗口Thread-0售出一张票剩余票数64
窗口Thread-1售出一张票剩余票数61
窗口Thread-0售出一张票剩余票数61
窗口Thread-2售出一张票剩余票数62
窗口Thread-1售出一张票剩余票数60
窗口Thread-2售出一张票剩余票数58
窗口Thread-0售出一张票剩余票数59
窗口Thread-0售出一张票剩余票数57
窗口Thread-2售出一张票剩余票数57
窗口Thread-1售出一张票剩余票数56
窗口Thread-2售出一张票剩余票数55
窗口Thread-0售出一张票剩余票数53
窗口Thread-1售出一张票剩余票数54
窗口Thread-1售出一张票剩余票数51
窗口Thread-0售出一张票剩余票数52
窗口Thread-2售出一张票剩余票数51
窗口Thread-2售出一张票剩余票数50
窗口Thread-1售出一张票剩余票数48
窗口Thread-0售出一张票剩余票数49
窗口Thread-0售出一张票剩余票数45
窗口Thread-2售出一张票剩余票数47
窗口Thread-1售出一张票剩余票数46
窗口Thread-2售出一张票剩余票数44
窗口Thread-1售出一张票剩余票数42
窗口Thread-0售出一张票剩余票数43
窗口Thread-0售出一张票剩余票数41
窗口Thread-1售出一张票剩余票数41
窗口Thread-2售出一张票剩余票数41
窗口Thread-2售出一张票剩余票数40
窗口Thread-1售出一张票剩余票数40
窗口Thread-0售出一张票剩余票数39
窗口Thread-1售出一张票剩余票数38
窗口Thread-0售出一张票剩余票数38
窗口Thread-2售出一张票剩余票数38
窗口Thread-1售出一张票剩余票数37
窗口Thread-0售出一张票剩余票数37
窗口Thread-2售出一张票剩余票数37
窗口Thread-1售出一张票剩余票数36
窗口Thread-2售出一张票剩余票数34
窗口Thread-0售出一张票剩余票数35
窗口Thread-1售出一张票剩余票数33
窗口Thread-0售出一张票剩余票数33
窗口Thread-2售出一张票剩余票数32
窗口Thread-0售出一张票剩余票数31
窗口Thread-1售出一张票剩余票数30
窗口Thread-2售出一张票剩余票数29
窗口Thread-2售出一张票剩余票数28
窗口Thread-1售出一张票剩余票数26
窗口Thread-0售出一张票剩余票数27
窗口Thread-0售出一张票剩余票数24
窗口Thread-1售出一张票剩余票数23
窗口Thread-2售出一张票剩余票数25
窗口Thread-2售出一张票剩余票数22
窗口Thread-0售出一张票剩余票数22
窗口Thread-1售出一张票剩余票数21
窗口Thread-1售出一张票剩余票数20
窗口Thread-0售出一张票剩余票数18
窗口Thread-2售出一张票剩余票数19
窗口Thread-0售出一张票剩余票数17
窗口Thread-2售出一张票剩余票数16
窗口Thread-1售出一张票剩余票数17
窗口Thread-1售出一张票剩余票数15
窗口Thread-2售出一张票剩余票数15
窗口Thread-0售出一张票剩余票数15
窗口Thread-0售出一张票剩余票数14
窗口Thread-1售出一张票剩余票数14
窗口Thread-2售出一张票剩余票数14
窗口Thread-0售出一张票剩余票数13
窗口Thread-2售出一张票剩余票数13
窗口Thread-1售出一张票剩余票数12
窗口Thread-0售出一张票剩余票数10
窗口Thread-2售出一张票剩余票数11
窗口Thread-1售出一张票剩余票数9
窗口Thread-0售出一张票剩余票数7
窗口Thread-1售出一张票剩余票数6
窗口Thread-2售出一张票剩余票数8
窗口Thread-2售出一张票剩余票数5
窗口Thread-1售出一张票剩余票数4
窗口Thread-0售出一张票剩余票数4
窗口Thread-2售出一张票剩余票数2
窗口Thread-0售出一张票剩余票数3
窗口Thread-1售出一张票剩余票数3
窗口Thread-2售出一张票剩余票数1
窗口Thread-1售出一张票剩余票数1
窗口Thread-0售出一张票剩余票数1
窗口Thread-0售出一张票剩余票数0
窗口Thread-2售出一张票剩余票数-2
卖完啦
窗口Thread-1售出一张票剩余票数-1
卖完啦
卖完啦
与目标VM断开连接, 地址为: ''127.0.0.1:59981',传输: '套接字'', 传输: '{1}'

进程已结束,退出代码0

在进程最后的几组线程执行,我们不难发现,剩余票数变成了负数,出现了售票超出的情况,通过韩顺平老师的讲解,设计线程的同步,之后的学习中,会学习到Synchronized来解决这一问题。

多线程是坦克大战项目中的核心,需要深刻理解运行机制,感谢韩老师的耐心讲解,有不足和错误的地方,欢迎指正。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值