线程的介绍

线程与进程

进程:

1.指在运行中的程序,例如使用微信就启动一个进程,操作系统就会为 该进程分配内存空间;

2.进程是程序的一次执行的过程,或者是正在运行的一个程序;是动态过程,有它自身的产生、存在和消亡的过程。

线程:

1.线程由进程创建的,是进程的一个实体;

2.一个进程可以拥有多个线程;

3.单线程:同一时刻,只允许执行一个线程;

4.多线程:同一时刻,可以执行多个线程。

并发和并行

并发:

同一时刻,多个任务交替执行;单核CPU实现的多任务就是并发

并行:

同一个时刻,多个任务同时执行,多核CPU可以实现并行

线程的使用

继承Thread创建线程,重写run方法

public static void main(String[] args) throws InterruptedException {
​
    //创建Dog对象,可以当做线程使用
    Dog dog = new Dog();
    //启动线程,执行dog的run方法
    dog.start();
​
    //当main线程启动一个子线程 Thread -0,主线程不会阻塞,而是继续执行
    //主线程和子线程交替执行
​
    for (int i = 0; i < 80; i++) {
        System.out.println("主线程 i = " + i + Thread.currentThread().getName());
        Thread.sleep(1000);
    }
​
}
//演示通过继承Thread来创建线程
/*说明:
* 1.当一个类继承Thread类,该类就可以做为线程使用
* 2.需要重写run方法,在run方法里面写自己需要实现的结果
* 3.Thread类中的run方法,是Thread类实现了Runnable接口的run方法
* */
​
class Dog extends Thread{
​
    @Override
    public void run() {//重写run方法,设置自己需要的实现的结果
​
        int temp = 0;
        while (true) {
            temp ++;
            //该线程在1s钟,在控制台输出:汪汪汪...
            System.out.println("汪汪汪..." + "循环次数:" + temp +  Thread.currentThread().getName());
            //让线程休息1s
            try {
                Thread.sleep(1000);//1000 = 1s
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
​
            //当循环20次后退出循环
            if(temp == 100){
                break;
            }
        }
​
    }
}

实现Runnable接口,重写run方法

说明:

1.JAVA是单继承的,在某些情况下一个类可能已经继承了某个父类,这是就不能再去继承Thread类方法来创建线程。

2.因此在上面那种情况下,就只能使用提供的另一个方法创建线程,通过实现Runnable接口创建线程。

public static void main(String[] args) {
​
    Tiger tiger = new Tiger();
​
    //调用Thread类来调用start方法去实现
    Thread thread = new Thread(tiger);
    thread.start();
​
}
class Tiger implements Runnable{
​
    int count = 0;
​
    @Override
    public void run() {//普通方法
        while (true){
            count ++;
            System.out.println("小老虎..." + count + Thread.currentThread().getName() );
​
            try {
                Thread.sleep(1000);//延时1s
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
​
            if(count == 20){
                break;
            }
        }
​
    }
}

使用jconsole监控进程执行情况

多个子线程案例

public static void main(String[] args) {
​
    //在main线程中启动两个子线程
    Banana banana = new Banana();
    Thread thread = new Thread(banana);
    thread.start();
​
    Apple apple = new Apple();
    Thread thread1 = new Thread(apple);
    thread1.start();
}
//每隔1s输出,且输出100次
class Banana implements Runnable{
​
    @Override
    public void run() {
​
        int num01 = 0;
        while (true){
            num01 ++;
            System.out.println("Hello World" + num01 + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
​
            if (num01 == 10){
                break;
            }
​
        }
​
    }
}
​
//
class Apple implements Runnable{
​
    @Override
    public void run() {
        int num02 = 0;
        while (true){
            num02++;
​
            System.out.println("hi ..." + num02 + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
​
            if (num02 == 5){
                break;
            }
​
        }
​
    }
}

继承Thread和实现Runnable接口的区别

  1. 通过继承Thread或者实现Runnable接口来创建线程本质是没有区别的;Thread类的本身就实现了Runnable接口

  2. 实现Runnable接口方式更加适合多个线程共享一个资源的情况,并且避免了单继承的限制,建议一般情况下使用Runnable接口

练习题:实现多线程售票问题

public static void main(String[] args) {
​
    //使用多线程,模拟三个窗口同时售票
   /* //第一种方法:使用Thread类
    SellTicket01 sellTicket01 = new SellTicket01();
    SellTicket01 sellTicket02 = new SellTicket01();
    SellTicket01 sellTicket03 = new SellTicket01();
​
    sellTicket01.start();
    sellTicket02.start();
    sellTicket03.start();*/
​
    //第二种方法:实现Runnable接口
    SellTicket02 sellTicket02 = new SellTicket02();
​
    Thread thread01 = new Thread(sellTicket02);
    Thread thread02 = new Thread(sellTicket02);
    Thread thread03 = new Thread(sellTicket02);
​
    thread01.start();
    thread02.start();
    thread03.start();
​
}
//第一种方法:继承Thread
class SellTicket01 extends Thread{
​
    //总票数100张
    private static int num = 100;
​
    @Override
    public void run() {
​
        while (true){
            if (num <= 0){
                System.out.println("票已售完...");
                break;
            }
​
            --num;
            System.out.println("售票处:" + Thread.currentThread().getName() + "\t" + 
                              "售出一张票" + "\t" + "剩余票数=" + num);
            //延时1s
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
	//第二种方法:实现Runnable接口
//第一种方法:继承Thread
class SellTicket02 implements Runnable{

    //总票数100张
    private  int num = 100;

    @Override
    public void run() {

        while (true){
            if (num <= 0){
                System.out.println("票已售完...");
                break;
            }
            
            --num;
            System.out.println("售票处:" + Thread.currentThread().getName() + "\t" +
           						 "售出一张票" + "\t" + "剩余票数=" + num);
            //延时1s
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

通知程序退出(程序终止)

1.当线程完成任务后,会自动退出

2.可以通过使用变量来控制run方法退出的方式停止线程,即通知方式

public static void main(String[] args) throws InterruptedException {

    Peach peach = new Peach();
    peach.start();

    //先延时10s,将线程停止退出
    Thread.sleep(10*1000);
    //停止线程
    peach.setLoop(false);

}
class Peach extends Thread{

    private int num = 0;
    private boolean loop = true;

    //可修改loop
    public void setLoop(boolean loop) {
        this.loop = loop;
    }

    @Override
    public void run() {

        while (loop){
            num ++;
            System.out.println("Peach线程正在执行..." + "\t"+Thread.currentThread().getName() + "\t" +num);

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

    }
}

线程中断

1.setName //设置线程名称,使与参数name相同

2.getName //返回该线程的名称

3.start //使该线程开始执行

4.run //调用线程对象run方法

5.setPriority //更改线程的优先级

6.getPriority //获取线程的优先级

7.sleep //在指定的毫秒数内让当前正在执行的线程休眠(暂时执行)

8.interrupt //中断线程

注意:

1.start底层会创建新的线程,调用run,run就是一个方法的调用,不会启动新的线程

2.线程优先级的范围:MAX_PRIORITY = 10 ;MIN_PRIORITY = 1;NORM_PRIORITY = 5

3.interrupt,中断程序;并未使得程序结束只是暂停;一般用于中断正在休眠的线程

4.sleep;线程的静态方法。使得当前线程休眠

public static void main(String[] args) throws InterruptedException {

    Lemon lemon = new Lemon();
    lemon.setName("线程01");//修改线程名称
    lemon.setPriority(Thread.MIN_PRIORITY);//设置优先级:最低
    lemon.start();

    System.out.println(lemon.getName());

    for(int j = 0 ;j < 5;j++){
        Thread.sleep(1000);
        System.out.println("hello..." + j);
    }

    lemon.interrupt();//执行到中断方法,就会中断lemon线程的休眠

}
class Lemon extends Thread{

    @Override
    public void run() {

        while (true) {
            for (int i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName() + "吃柠檬..." + i);
            }

            System.out.println(Thread.currentThread().getName() + "吃柠檬..." + "休眠中...");
            try {
                Thread.sleep(50 * 1000);
            } catch (InterruptedException e) {
                System.out.println(Thread.currentThread().getName() + "吃柠檬..." + "被interrupt ...");
            }

        }
    }
}

线程插队

1.yield:线程的礼让

让出CPU,让其他线程执行,但礼让的时间不确定,所以也不一定成功

2.join:线程插入

插队的线程一旦插队成功,则肯定先执行完插入的线程所有的任务

public static void main(String[] args) throws InterruptedException {

    Mango mango = new Mango();
    mango.start();

    for (int i = 0; i < 10; i++) {

        Thread.sleep(1000);
        System.out.println(Thread.currentThread().getName()+ "\t" + "吃猕猴桃..." +
        							"\t" + i);

        if (i == 5){
            System.out.println("主线程让子线程先执行完...");
            mango.join();//插队处理:让子线程提前执行
            //Thread.yield();//让子线程提前执行,但不一定成功
        }

    }

}
class Mango extends Thread{

    int num = 0;
    @Override
    public void run() {

        while (true) {


            for (int i = 0; i < 10; i++) {
                num ++;

                try {
                    Thread.sleep(1 * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "\t" + "吃芒果..." + 									"\t" + i);
            }
            if (num == 20){
                break;
            }

        }
    }
}

线程插队练习:

1.主线程每隔1s,输出hi,一共10次 2.当输出到hi 5时,启动一个子线程(要求 实现Runnable),每隔1s输出hello,等该线程输出10次hello后,退出 3.主线程继续输出hi,直到主线程退出.

public static void main(String[] args) throws InterruptedException {

    Almond almond = new Almond();
    Thread thread = new Thread(almond);

    for (int i = 0; i < 10; i++) {

        Thread.sleep(1000);
        System.out.println("线程:" + Thread.currentThread().getName() + "\t" + "hi..."+
                        "\t" + i);

        if (i == 5){
            System.out.println("允许子线程执行...");
            thread.start();//开启子线程
            thread.join();//将所有空间给子线程执行
        }
    }

}
//定义一个类并实现Runnable接口
class Almond implements Runnable{

    int num = 0;
    @Override
    public void run() {

        while (true){
            num++;
            try {
                Thread.sleep(1000);
                System.out.println("线程:" + Thread.currentThread().getName()+
                                "\t" + "hello..." + "\t" + num);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (num == 10){
                break;
            }
        }

    }
}

守护线程

用户线程和守护线程

1.用户线程:就是工作线程,当线程的任务执行完或通知方式结束

2.守护线程:一般是为工作线程服务的,当所有的用户线程结束,守护线程自动结束

3.常见的守护线程:垃圾回收机制

public static void main(String[] args) throws InterruptedException {

    Grape grape = new Grape();
    //1.如果希望当main线程结束后,子线程自动结束
    //2.只需要将子线程设为守护线程
    grape.setDaemon(true);//将子线程设为守护线程

    grape.start();

    for (int i = 0; i < 10; i++) {//主线程
        System.out.println("线程:" + Thread.currentThread().getName() + "\t" + "吃猕猴桃" +
                            "\t" + i);
        Thread.sleep(1000);
    }

}
class Grape extends Thread{

    int num = 0;
    @Override
    public void run() {

        while (true) {
                num ++;

                try {
                    Thread.sleep(1 * 1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + "\t" + "吃葡萄..."
                                    + "\t" + num);

        }
    }
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

jhan&

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

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

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

打赏作者

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

抵扣说明:

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

余额充值