多线程(一)

为什么要有多线程

在没有多线程的时候,计算机的工作是依靠进程之间并发执行的,但是由于进程之间创建销毁或者是切换的开销较大,所以延伸出"多线程"的概念.

线程可以理解为"轻量级的进程",线程的创建销毁以及线程之间的切换的开销比进程要小得多.

除此之外,由于进程之间是相互隔离的,彼此要进行通信比较麻烦,但是对于同一个进程的多个线程,彼此共享同一份资源,线程之间的通信也较为简单.

多线程

多线程,就是多个线程并发执行,满足同时完成多个任务的需求.

多线程的特点

  • 每个线程都是独立的执行流,彼此之间并发执行
  • 可以通过代码实现对线程执行顺序的控制

多线程的代码实现

java标准库提供了一个Thread类,用来控制一个线程.

继承Thread类重写run方法

class MyThread extends Thread {
    @Override
    public void run() {
    	//方法实现
    }
}
public class ThreadDemo1 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new MyThread();
        t.start();
    }
}

上述方法涉及到两个线程,一个是main方法对应的主线程(一个进程中至少需要一个线程),另外一个是t对应的线程

当我们点击运行按钮,运行我们的代码时,这个时候idea对应的进程就会帮我们自动创建一个新的Java进程,这个进程用来执行我们写的代码,这个进程包含两个线程,一个时主线程,一个是t线程

 

各个线程之间是独立的执行流代码展示

class MyThread extends Thread{
    @Override
    public void run() {
        while (true) {
            System.out.println("hello t");
        }
    }
}
public class ThreadDemo2 {

    public static void main(String[] args) {
        Thread t = new MyThread();
        t.start();
        while (true) {
            System.out.println("hello main");
        }
    }

}

 运行结果展示

分析

  • 对于以上代码,如果是单核CPU,代码的执行顺序是执行到t.statr()方法后,开启新线程,之后这两个线程交替执行,但是由于线程之间的调度是随机的,所以不一定严格遵守两个线程轮流执行
  • 如果是多核CPU,代码的执行顺序是执行到t.statr()方法后,开启新线程,那么在当前只有两个线程的情况下,main和t线程同时执行

实现Runnable接口重写run方法

public class  MyRunnable implement Runnable {
    @Override
    public void run() {
        // 重写run方法    
    }
}
public class ThreadDemo2 {
    public static void main (String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread t = new Thread(myRunnable);
        t.start();
    }
}

继承Thread类的匿名内部类写法

public static void main(String[] args) {
    Thread t = new Thread() {
        @Override
        public void run() {
            // 方法体
        }
    };
}

实现Runnable接口的匿名内部类写法

public static void main(String[] args) {
    Thread t = new Thread(new Runnable () {
        @Override
        public void run() {
            // 方法体
        }
    });
}

以上四种多线程的代码实现都不是最推荐的写法,最推荐的写法是通过lambda表达式实现多线程

lambda表达式实现

lambda表达式的基本写法 (参数列表)->{ // 方法体 }

public static void main(String[] args[]) {
    Thread t = new Thread(()->{
        // 方法体
    });
}

Thread类

多线程的控制类,一个Thread对象控制一个线程.通过Thread对象实现对线程的开始/暂停/结束的控制

Thread的属性

属性

获取方法
IDgetId()
名称getName()
状态getState()
优先级getPriority()
是否是后台线程isDaemon()
是否存活isAlive()
是否被中断isInterrupted()

  • ID是线程的唯一标识,不同线程不会重复,类似于人类世界的身份证
  • 名称是线程的名字,对线程命名有利于进行调试
  • 状态是标识线程当前所处的状态,线程的状态有NEW ,  RUNNABLE , BLOCKED , WAITING , TIMED_WAITING , TERMINATED
  • 优先级高的线程理论上来说会更容易被调度到
  • 后台线程,表示该线程不需要等到所有线程结束才能结束
  • 存活,当thread类的run方法还没有被调用或者是运行结束就意味着当前线程不存活了,但是该线程对应的实例可能还是存在的.
  • 线程的中断,该线程执行过程中被打断了

后台线程和前台线程

  • 前台线程:应用程序(进程)必须运行完所有的前台线程才能退出
  • 后台线程:应用程序可以不考虑后台线程是否已经运行完毕而直接退出,所有的后台线程在应用程序退出时自动结束.

举个例子:银行的对外下班时间是五点,那么五点过后,就不会再继续坐在柜台对顾客提供服务了,但是在五点过后,银行内部需要对今天的业务进行整理和总结后才能下班.

那么在这个例子中,银行就是应用程序,来银行的顾客就是后台线程,我们的银行不需要等到将所有顾客都服务好了才关门,才是到点了不管你有没有被服务都关门,而银行的业务则是前台线程,只有把业务全部完成了,银行工作人员才能真正的下班.

前台线程和后台线程的区别和联系

  • 前台线程会阻止进程的结束,必须进程中的所有前台进程执行完,进程才能结束;后台线程不会阻止进程的结束,哪怕后台进程还没执行完,进程也会结束。
  • 属于某个进程的所有前台线程都终止后,该进程就会被终止。所有剩余的后台线程都会停止且不会完成。
  • 托管线程池中的线程都是后台线程,使用new Thread方式创建的线程默认都是前台线程。可以通过setDaemon()方法将前台进程设置为后台进程

Thread的方法

构造方法

方法

说明

Thread()

创建一个线程对象
Thread(Runnable target)

使用runnable对象创建线程对象

Thread(String name)创建线程对象,并命名
Thread(Runnable target ,String name)使用Runnable对象创建线程对象,并命名
Thread t1 = new Thread();
Thread t2 = new Thread(new MyRunnable());
Thread t3 = new Thread("我是线程的名字");
Thread t4 = new Thread(new MyRunnable(), "我是线程的名字");

如果不对线程进行命名,那么系统会自动以 Thread-数字的形式对线程进行命名,对线程命名有利于对代码的调试

Thread的普通方法

启动一个线程

调用start()方法意味着真正的创建了一个线程,线程内部会自动执行run方法

而run()方法则是说明了线程要做的事情,仅仅调用run()方法无法真正创建出一个线程.

中断一个线程

获取当前线程引用

方法说明
public static Thread currentThread();返回当前线程对象的引用

该方法是静态方法,使用Thread类调用,就会返回当前所在的线程

public class Demo {
    public static void main(String[] args) {
        Thread t = new Thread(()->{
            // 获取t线程的引用
            System.out.println(Thread.currentThread());
        });
        t.start();
        // 获取主线程的引用
        System.out.println(Thread.currentThread());
    }
}

等待一个线程

在一些情况下,线程之间存在先后关系,某些线程的执行要等另外的线程执行完毕才能执行.例如,在银行存钱,必须先开户,只有开户了才能存钱.

方法

说明
public void join()等待线程结束
public void join(long mills)等待线程结束,最多等待mills毫秒

休眠当前线程

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值