【JavaSE】多线程篇(2)线程的基本使用与机制


1.线程的基本使用

创建线程的几种方式:
1.继承Thread类,重写run方法
2.继承Thread,使用匿名内部类
3.实现Runnable接口,重写run方法
4.实现Runnable,使用匿名内部类
5.创建线程最推荐的写法,使用lambda表达式最简单最直观的写法~~

tmp66D.png

1.1继承Thread类

  1. 当一个类继承了Thread类,该类就可以当作线程使用
  2. 重写run方法,在里面会写上自己的业务代码

代码演示:继承Thread类,重写run方法

package Thread;
class Fj extends Thread {//创建一个类继承Thread
    @Override
    public void run() {//重写run方法
        while (true) {
            System.out.println("hello");
            try {
                Thread.sleep(1000);//休眠1秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class ThreadDemo1 {

    public static void main(String[] args) {
        Thread fj = new Fj();
        fj.start();//启动线程
        //该线程每隔一秒输出hello
    }
}

1.2继承Thread,使用匿名内部类

1.创建一个匿名内部类,继承Thread类重,写run方法
2.new 这个匿名内部类的实例
代码演示:继承Thread,使用匿名内部类

public class ThreadDemo1 {
    public static void main(String[] args) {
        Thread fj=new Thread(){//匿名内部类
            @Override
            public void run() {
                System.out.println("hello fj");
            }
        };
        fj.start();//启动线程
        System.out.println("hello main");
    }
}

1.3实现Runnable接口,重写run方法

由于java是单继承的,在某些情况下,一个类可能已经继承了某个父类,这时再用继承Thread类的方法来创建线程显然是不可能的了。
因此,java设计者,提供了另一种方法,就是通过实现Runnable接口来创建线程
代码演示:实现Runnable接口

package Thread;
class MyRunnable implements Runnable {
    @Override
    public void run() {
        while (true) {
            System.out.println("hello fj");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class ThreadDemo2 {
    public static void main(String[] args) {
        MyRunnable runnable = new MyRunnable();
        Thread fj = new Thread(runnable);
        fj.start();
        while (true) {
            System.out.println("hello main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

1.4实现Runnable,使用匿名内部类

代码演示

package Thread;
public class ThreadDemo3 {
    public static void main(String[] args) {
        Thread fj=new Thread(){
            public void run() {
                while (true) {
                    System.out.println("hello fj");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        };
        fj.start();
        while (true){
            System.out.println("hello main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

1.5创建线程最推荐的写法使用lambda表达式!

lambda表达式,本质就是一个匿名函数
Java里面,函数(方法)是无法脱离类的,lambda就相当于是一个例外
lambda表达式的基本写法:
()->{ }
()里面放参数。
如果只有一个参数()可以省略
{ }里面放函数体
代码演示:lambda表达式

package Thread;
public class ThreadDemo5 {
    public static void main(String[] args) {
        Thread fj=new Thread(()->{
            while (true){
                System.out.println("hello fj");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        fj.start();
        while (true){
            System.out.println("hello main");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

2多线程机制

通过Thread.currentThread().getName()来获取当前线程的名称
代码演示:创建一个线程获取他的名称

package Thread;
class Fj extends Thread {//创建一个类继承Thread
    @Override
    public void run() {//重写run方法
        while (true) {
            System.out.println("hello fj"+"线程名"+Thread.currentThread().getName());
            try {
                Thread.sleep(1000);//休眠1秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class ThreadDemo1 {

    public static void main(String[] args) {
        Thread fj = new Fj();
        fj.start();//启动线程

    }
}

tmpEC81.png
在主线程添加一些业务代码观察执行过程
代码演示

package Thread;
class Fj extends Thread {//创建一个类继承Thread
    @Override
    public void run() {//重写run方法
        while (true) {
            System.out.println("hello fj"+"线程名"+Thread.currentThread().getName());
            try {
                Thread.sleep(1000);//休眠1秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class ThreadDemo1 {

    public static void main(String[] args) {
        Thread fj = new Fj();
        fj.start();//启动线程
        for (int i = 0; i <10; i++) {
            System.out.println("主线程执行中"+i);
            try {
                Thread.sleep(1000);//同样休眠一秒;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

tmpFBEB.png
可见main线程和Thread-0线程交替执行

如图所示:上述程序 执行过程中,会打开一个进程,进入main主线程。当执行start时,会执行Thread-0子线程
当main线程启动一个子线程 Thread-0, 主线程不会阻塞, 会继续执行
tmpD200.png

3Thread类中run和start的区别

通过上述代码我们看到,无论以哪种方式创建,最终我们都会重写一个叫做 run 的方法,那为什么不直接调用run方法而是通过start呢?
代码演示:直接调用run方法

package Thread;
class Fj extends Thread {//创建一个类继承Thread
    @Override
    public void run() {//重写run方法
        while (true) {
            System.out.println("hello fj"+"线程名"+Thread.currentThread().getName());
            try {
                Thread.sleep(1000);//休眠1秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class ThreadDemo1 {
    public static void main(String[] args) {
        Thread fj = new Fj();
        //fj.start();//启动线程
        fj.run();
        for (int i = 0; i <10; i++) {
            System.out.println("主线程执行中"+i);
            try {
                Thread.sleep(1000);//同样休眠一秒;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

tmp1F50.png
如果直接调用run方法则在主线程中运行
run方法就是一个普通的方法,没有真正的启动一个线程,就会阻塞在这里,直到run方法执行完毕才继续执行后续代码

Thread.java中start()方法的源码如下

public synchronized void start() {
    // 如果线程不是"就绪状态",则抛出异常!
    if (threadStatus != 0)
        throw new IllegalThreadStateException();

    // 将线程添加到ThreadGroup中
    group.add(this);

    boolean started = false;
    try {
        // 通过start0()启动线程
        start0();
        // 设置started标记
        started = true;
    } finally {
        try {
            if (!started) {
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {
        }
    }
}

start() : 它的作用是启动一个新线程,新线程会执行相应的run()方法.
start0()是本地方法,是JVM调用,底层是c/c++实现
真正实现多线程的效果,是start0(),而不是run

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值