Java 多线程基础(一)

多线程继承关系: 两种实现方式:①继承Runnable实现子类Thread,重写run()方法,②实现Runnable接口,重写run方法

①继承Thread类创建线程 

package com.edu.threaduse;

/**
 * @author mtl121
 * @version 1.0
 */
public class Thread01 {
    public static void main(String[] args) throws InterruptedException {
        //创建一个Cat对象,可以当作线程使用
        Cat cat = new Cat();
/*
        (1)
        public synchronized void start() {
            ...
            start0()
            ...
        }
        (2)
        //start0() 是本地方法,是 JVM 调用, 底层是 c/c++实现
        //真正实现多线程的效果, 是 start0(), 而不是 run
        private native void start0();
        */
        cat.start();//启动线程-> 最终会执行 cat 的 run 方法
        //当main线程启动一个子线程,主线程main不会阻塞, 会继续执行, 表现为主线程和子线程交替执行
        //当主线程结束不会造成进程的结束,如果子线程未结束,线程也不会结束,只有当所有子线程均运行结束,进程才会结束
        System.out.println("主线程名:" + Thread.currentThread().getName());
        for(int i = 0; i < 50; i++){
            System.out.println("主线程 i=" + i);
            //让主线程休眠1s
            Thread.sleep(1000);
        }
    }
}

// 当一个类继承了Thread类,该类就可以当作线程使用
// 我们回重写run方法,在run中写上自己的业务代码
// Thread的run方法是重写的Runnable接口的run方法
class Cat extends Thread {
    int times = 0;
    @Override
    public void run() {
        while (true) {
            System.out.println("喵喵,我是小猫咪" + (++times) + "进程名:" + Thread.currentThread().getName());
            //线程休眠1秒, ctrl + alt + t生成trycatch代码块
            try {
                //让线程休眠1s
                Thread.sleep(1000);//单位毫秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(times == 80){
                break;// 当times到8 ,退出while,线程结束
            }
        }
    }
}

   主线程可以开多个子线程,子线程还可以开子线程

关于调用Start()启动线程,而不是直接调用run方法的原因

cat.start();//启动线程,-> 最终会执行 cat 的 run 方法
cat.run();//直接调用run的话,run 方法就是一个普通的方法, 没有真正的启动一个线程,就会把 run 方法执行完毕,才向下执行,并不会交替执行

②实现Runnable接口创建线程

使用这种方法的原因:Java是单继承的,某些情况下一个类可能已经继承了某个父类,这时就不能通过继承Thread类创建线程了,因此提供这种方式来创建线程

有了Thread,为什么还要有Runnable?
1、为多继承提供可能。
对于类继承,java只允许单继承模式,如果你需要设计一个类既继承业务类拥有某个业务类功能,又继承线程对象Thread类具有多线程的功能,那么Thread类就无法满足你的要求。这时候就要选择Runnable。更多的接口优于抽象类的内容可参考《Effect Java》中的第16条原则,这里不赘述。

2、实现数据的共享。
首先我们知道,Thread线程对象调用run()方法是采用回调的机制。其次,每个Thread线程对象只能调用一次start方法启用一个线程。因此,把数据放在Thread对象中,并不能被多个线程所共享。java为我们提供了Runnable接口,就很好的解决了这个问题。我们把要操作的数据封装入Runnable的实现类中,然后将Runnable实例传入多个Thread对象中,就可以实现一个对象数据在多个线程的共享了

package com.edu.threaduse;

/**
 * @author mtl121
 * @version 1.0
 * 通过实现Runnable接口来开发线程
 */
public class Thread02 {
    public static void main(String[] args) {
//        Dog dog = new Dog();
//        //dog.start(); 不能调用start方法
//        //创建了 Thread 对象,把 dog 对象(实现 Runnable),放入 Thread,底层使用了代理设计模式
//        Thread thread = new Thread(dog);
//        thread.start();

        Tiger tiger = new Tiger();//Tiger实现了Runnable接口
        ThreadProxy threadProxy = new ThreadProxy(tiger);//传入tiger
        threadProxy.start();
    }
}

class Animal{}

class Tiger extends Animal implements Runnable{

    @Override
    public void run() {
        System.out.println("老虎嗷嗷叫");
    }
}

//线程代理类, 实现了简单的Thread类
class ThreadProxy implements Runnable {

    private Runnable target = null;

    @Override
    public void run() {
        if(target != null){
            target.run();
        }
    }

    public ThreadProxy(Runnable target) {
        this.target = target;
    }

    public void start(){
        start0();
    }

    private void start0() {
        run();
    }
}

class Dog implements Runnable {

    int count = 0;
    @Override
    public void run() {
        while(true){
            System.out.println("小狗汪汪叫" + (++count) + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if(count == 8){
                break;
            }
        }
    }
}

案例一:实现多线程售票

package com.edu.threaduse;

/**
 * @author mtl121
 * @version 1.0
 */
public class sellTicket {
    public static void main(String[] args) {
        Ticket ticket1 = new Ticket();
        ticket1.start();
        Ticket ticket2 = new Ticket();
        ticket2.start();
        Ticket ticket3 = new Ticket();
        ticket3.start();
        Ticket ticket4 = new Ticket();
        ticket4.start();
        Ticket ticket5 = new Ticket();
        ticket5.start();
        //继承Thread和实现Runnable接口的区别
        //从Java设计来看,本质一样,Thread类也是实现Runnable接口,
        //但是从用法上来看,实现Runnable接口更适合多个线程共享一个资源的情况
//        Ticket1 ticket1 = new Ticket1();
//        new Thread(ticket1).start();//将同一个对象放入不同的线程保证了共享count票数
//        new Thread(ticket1).start();
//        new Thread(ticket1).start();
    }
}

class Ticket extends Thread{
    static int count = 100;
    @Override
    public void run() {
        while(true){

            if(count <= 0){
                System.out.println("售票结束");
                break;
            }
            try {
                Thread.sleep(50);
                System.out.println(String.format("还剩下%d张票", --count) + Thread.currentThread().getName());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    }
}
class Ticket1 implements Runnable{
    int count = 100;
    @Override
    synchronized public void run() {
        while(true){
            count --;
            System.out.println(String.format("还剩下%d张票", count) + Thread.currentThread().getName());
            if(count <= 0){
                System.out.println("售票结束");
                break;
            }
        }
    }
}

线程终止(通知方式) 

package com.edu.threaduse;

/**
 * @author mtl121
 * @version 1.0
 */
public class ThreadExit {
    public static void main(String[] args) throws InterruptedException {
        T t1 = new T();
        t1.start();
        //如果希望main线程控制子线程t1的终止,必须可以修改loop
        Thread.sleep(1000);
        //使用通知的方式让t1退出run方法;
        t1.setLoop(false);
    }
}

class T extends Thread{
    private int count = 0;
    //控制变量
    private boolean loop = true;
    @Override
    public void run() {
        while(loop){
            try {
                Thread.sleep(50);
            } catch (InterruptedException e) {//当调用该线程的interrupt方法时,就会catch一个中断异常
                e.printStackTrace();
            }
            System.out.println("T 运行中..." + (++count));
        }
    }

    public void setLoop(boolean loop){
        this.loop = loop;
    }
}

注意事项和细节

start()底层会创建新的线程,调用run方法,run方法就是一个简单的方法调用,不会启动新线程

②线程优先级范围:

③interrept: 中断进程,但是并没有真正的终止进程,所以一般用于中断正在休眠的进程(打断线程的休眠[sleep])

④sleep :线程的静态方法,用于使当前的线程休眠

package test2;
import test1.*;
/**
 * @author mtl121
 * @version 1.0
 */
public class test2 {
    public static void main(String[] args) throws InterruptedException {
        T2 t2 = new T2();
        t2.start();
        for(int i = 0; i <= 20; i++){
            Thread.sleep(1000);
            System.out.println("主线程 吃了" + i + "包子");
            if(i == 5){
//                t2.join();//要先启动线程才能join
                Thread.yield();
            }
        }
    }
}

class T2 extends Thread {
    @Override
    public void run() {
        for(int i = 0; i <= 20; i++){
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("子线程 吃了" + i + "包子");
        }
    }
}

前文说到主线程结束不会导致整个进程的结束,而是要等待所有的线程都执行完毕才能结束进程。但是如果需要完成这样的需求:主线程结束,子线程跟着结束

只需要将子线程设置为守护线程即可:

package com.edu.threaduse;

/**
 * @author mtl121
 * @version 1.0
 */
public class Thread_home {
    public static void main(String[] args) throws InterruptedException {
        for(int i = 0; i < 10; i++){
            System.out.println("hi" + (i + 1));
            Thread.sleep(1000);
            if(i == 4){
                T2 t2 = new T2();
                Thread thread = new Thread(t2);
                thread.setDaemon(true);
                thread.start();
            }
        }
        System.out.println("主线程结束");
    }
}

class T2 implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println("hello" + (i + 1));
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Meikesibondwell

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

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

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

打赏作者

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

抵扣说明:

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

余额充值