Java学习之路(五十)| 线程(一)

本文详细介绍了Java中的多线程概念,包括程序、进程和线程的定义,以及创建线程的两种方式:继承Thread类和实现Runnable接口。通过多线程售票系统实例展示了并发问题,并讨论了线程终止的方法。强调了实现Runnable接口更适合资源共享和避免单继承限制。
摘要由CSDN通过智能技术生成

各自努力,最高处见!加油!

一、程序(program)

程序是为了完成任务、用某种语言编写的一组指令的集合。

二、进程

  1. 进程是指运行中的程序,比如我们使用qq,就启动了一个线程,系统会为该进程分配内存空间。当我们使用迅雷,又启动了一个进程,操作系统将为迅雷分配新的内存空间。
  2. 进程是程序的一次执行过程,或是正在运行的一个程序。是动态过程:有它自身产生、存在和消亡的过程

三、线程

(1)线程相关概念

  1. 线程是由进程创建的,是进程的一个实体
  2. 一个进程可以拥有多个线程
  3. 如:一个迅雷下载窗口中有多个线程在为我们下载几个不同的任务。
  4. 单线程:同一个时刻,只允许执行一个线程
  5. 多线程:同一个时刻,可以执行多个线程,比如:一个qq进程,可以同时打开多个聊天窗口,一个迅雷进程,可以同时下载多个文件。
  6. 并发:同一时刻,多个任务交替进行,造成一种“貌似同时”的错觉,简单的说,单核CPU实现的多任务就是并发。
  7. 并行:同一时刻,多个任务同时执行。多核CPU可以实现并行。

(2)线程的基本使用:创建线程的两种方式

  1. 继承Thread类,重写run方法。
  2. 实现Runnable接口,重写run方法。
  3. Thread类中的run方法是实现了Runnable接口的run方法。
    在这里插入图片描述

①继承Thread类,重写run方法。

示例代码:

public class Thread01 {
    public static void main(String[] args) {
        Cat cat=new Cat();
        cat.start();//启动线程,会自动调用Cat类中的run方法
        //说明:当main线程启动一个子线程Tread-0,主线程不会阻塞,会继续执行
        System.out.println("主程序继续执行:"+Thread.currentThread().getName());
        for (int i = 0; i < 10; i++) {
            System.out.println("主线程:"+i);
            Thread.sleep(1000);
        }
    }
}

//当一个类继承了Thread类,该类就可以当做线程使用
class Cat extends Thread{
    int time;
    @Override
    public void run() {
        //重写run方法,写上业务代码
        while(true) {
            System.out.println("快乐" + (++time));

            try {//Ctrl+alt+t
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在这里插入图片描述
疑问解答:为什么不直接在main方法中直接调用run方法?
解:直接在main方法中调用run方法的话,run方法是在main线程中执行,达不到多线程的效果。

在这里插入图片描述
在start方法的内部,调用的是start0()方法。start0方法是本地方法,由JVM调用,底层是C/C++实现。==>真正实现多线程的效果是start0(),而不是run方法。

start()方法调用start0()方法后,该线程并不一定会马上执行,只是将线程变成了可运行状态,具体什么时候执行,取决于CPU,由CPU同一调度。

②实现Runnable接口,重写run方法。

示例代码:

public class Thread023 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        Thread thread = new Thread(dog);//Thread类的静态代理模式
        thread.start();
    }
}

class Dog implements Runnable{

    int count=0;
    @Override
    public void run() {
        while(count<80){
            System.out.println("小狗"+(++count));

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

在代理模式中,最核心的还是调用了start0()方法,凡是多线程都离不开start0方法的调用。

多个线程:
在这里插入图片描述

(3)继承Thread与实现Runnable接口两种方法实现多线程的区别

  1. 从java的设计来看,两种方法没有本质区别,从jdk帮助文档来看,Thread类本省就实现了Runnable接口。start()–>start0()
  2. 实现Runnable接口方式更加适合多个线程共享一个资源的情况,并且避免了单继承的限制。
T3 t3=new T3("Hello");
Thread thread01=new Thread(t3);
Thread thread02=new Thread(t3);
thread01.start();
thread02.start();
System.out.println("主线程执行完毕");

(4)多线程售票系统

//三个窗口同时售票100张
public class SellTicket {
    public static void main(String[] args) {
//        SellTicket01 sellTicket01 = new SellTicket01();
//        SellTicket01 sellTicket02 = new SellTicket01();
//        SellTicket01 sellTicket03 = new SellTicket01();
//        sellTicket01.start();
//        sellTicket02.start();
//        sellTicket03.start();

        SellTicket02 sellTicket04=new SellTicket02();
        SellTicket02 sellTicket05=new SellTicket02();
        SellTicket02 sellTicket06=new SellTicket02();
        Thread thread1 = new Thread(sellTicket04);
        Thread thread2 = new Thread(sellTicket05);
        Thread thread3 = new Thread(sellTicket06);
        thread1.start();
        thread2.start();
        thread3.start();

    }
}

//使用继承Thread类的方式
class SellTicket01 extends Thread{
    private static int ticketNum=100;
    @Override
    public void run() {
        while (true){
            if(ticketNum<=0){
                System.out.println("售票结束");
                break;
            }
//            ticketNum--;
            //休眠50ms
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("窗口"+Thread.currentThread().getName()+"售出一张票"+"剩余票数:"+(--ticketNum));
            //将--的位置提前可以初步解决超卖的问题:即在剩余票数不足的情况下,三个线程同时售票导致出现负票数的情况。

        }
    }
}

//采用实现Runnable接口的方法
class SellTicket02 implements Runnable{
    private static int ticketNum=100;
    @Override
    public void run() {
        while (true){
            if(ticketNum<=0){
                System.out.println("售票结束");
                break;
            }
            //休眠50ms
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println("窗口"+Thread.currentThread().getName()+"售出一张票"+"剩余票数:"+(--ticketNum));
        }
    }
}

(5)线程终止

  1. 当线程完成任务后,会自动退出。
  2. 还可以通过使用变量来控制run方法退出的方式停止线程,即通知方式。

代码示例:启动一个线程t,要求在main线程中停止线程t,编程实现。

public class ThreadExit {
    public static void main(String[] args) throws InterruptedException {
        T t = new T();
        t.start();

        //让主线程休息10s后通知线程退出
        Thread.sleep(10*1000);
        t.setLoop(false);
    }
}

class T extends Thread{
    private int count=0;
    private boolean loop=true;
    @Override
    public void run() {
        while (loop){
            System.out.println("程序运行中。。。"+(++count));
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void setLoop(boolean loop) {
        this.loop = loop;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值