多线程(一)认识线程和Thread类

目录

一、认识线程(Thread)

1、什么是线程?

2、线程和进程的关系

3、多线程的优势

4、线程的状态

5、创建线程的方式

二、Thread类及其常用方法

1、Thread常见的构造方法

2、启动线程

3、线程的属性

4、Thread常用方法

三、多线程(内存的使用)


一、认识线程(Thread)

1、什么是线程?

一个线程就是一个“执行流”,每个线程之间都可以按照顺序执行自己的代码。多个线程之间“同时”执行着多份代码。

线程的实现方式:

  • 内核线程→Java中的线程,是基于内核线程的轻量级实现(轻量级进程:相比于进程,创建、调度、销毁效率要高的多)
  • 用户线程:用程序自己来实现线程,包括线程的调度等。(安卓以前的开发语言时Java,最新的是kotlin(运行在jvm上),里面使用的就是协议(用户线程))

2、线程和进程的关系

  • 进程与进程之间不共享内存空间,同一个进程的线程之间共享同一个内存空间
  • 进程是系统分配资源的最小单位,线程是系统调度的最小单位。
  • 线程的创建、调度、销毁的代价小于进程。
  • 进程包含线程,每个进程至少存在一个线程,即主线程。
  • 线程(出现bug可能导致整个进程挂掉),进程间是独立运行的(可能存在进程通信)

3、多线程的优势

多线程也存在其缺陷:线程的创建/销毁也有一定的开销(一般用于执行耗时比较长的任务);增加了编码的复杂程度。

“并发编程”成为刚需。

  • 充分利用cpu资源,提高执行效率。(单核cou的发展遇到瓶颈,要想提高计算力,就需要多核cpu。并发编程能充分利用多核cpu资源)
  • 有些任务场景需要“等待IO”,使用并发编程此时可以去做其他的事情。

4、线程的状态

线程的多种状态
  1.  new:创建态
  2. runnable:可运行态
    (程序无法判断某个时间是就绪态还是可运行态,所以这两个状态对程序没有意义)
  3. 等待、超时等待、阻塞。(这三种状态的特征都是程序在挂起来等)
  4. 销毁

5、创建线程的方式

(1)继承Thread类

  • 继承Thread来创建一个线程类
         public static void main(String[] args) {
            //继承的写法1.自定义一个类来继承Thread
            //创建一个线程
            MyThread myThread = new MyThread();
            //运行一个线程:申请系统调度运行
            myThread.start();
        }
    
        //继承的方式:1.继承Thread,2.重写run方法(定义要执行的任务代码)
        private static class MyThread extends Thread{
            @Override
            public void run() {
                System.out.println("mythread run");
            }
        }
  • 使用匿名内部类创建Thread子类对象
        public static void main(String[] args) {
    
            //继承的写法2.使用一个匿名内部类
            Thread t = new Thread(){//属于继承Thread但没有名称的子类
                @Override
                public void run() {
                    System.out.println("匿名内部类 run");
                }
            };
            t.start();
        }

(2)实现Runnable

  • 实现Runnable接口
        public static void main(String[] args) {
            //实现Runnable写法1
            Thread t1 = new Thread(new MyRunnable());
            t1.start();
        }
         private static class MyRunnable implements Runnable{
            @Override
            public void run() {
                System.out.println("MyRunnable run");
            }
        }
  • 匿名内部类创建Runnable子类对象
            //实现Runnable写法2:匿名内部类
            Runnable r2 = new Runnable() {//属于Runnable接口的实现类(没有名字)
                @Override
                public void run() {
                    System.out.println("匿名内部类run");
                }
            };
            Thread t2 = new Thread(r2);
            t2.start();
    
            //也可以把匿名内部类对象,直接写在构造方法的参数上
            Thread t3 = new Thread(new Runnable() {
                @Override
                public void run() {
                    System.out.println("匿名内部类run");
                }
            });
            t3.start();
    
  • 使用lambda表达式创建子类对象
        //了解:lambda表达式
        Thread t4 = new Thread(() -> System.out.println("匿名内部类run"));
        t4.start()

(3)实现Callable接口

二、Thread类及其常用方法

1、Thread常见的构造方法

方法 说明
Thread() 创建线程对象
Thread(Runnable target) 使用 Runnable 对象创建线程对象
Thread(String name) 创建线程对象,并命名
Thread(Runnable target, String name) 使用 Runnable 对象创建线程对象,并命名

2、启动线程

(1)start

thread.start();
//申请系统调度,执行thread中的任务(重写的run方法)

 main线程创建Thread的代码,没有执行重写的run方法。

 (2)start()和run()的区别

  • start:启动线程的方式;
  • run:属于线程任务的描述。

 (3)多个线程,同时存在并发和并行的现象

观察以下代码:

 main线程在执行到t.start()时,才会启动t线程,t线程的run中代码行和main线程的打印代码行执行顺序是随机的/无序的(但t线程启动后,系统调度才会执行run方法,这是过程是需要耗时的,所以先打印main的代码行)。

3、线程的属性

属性 获取方法
ID getId()
名称 getName()
状态 getState()
是否后台线程 isDaemon()
是否存活 isAlive()
是否被中断 isInterrupted()
  • ID是线程的唯一标识,不同线程不会重复
  • 状态表示当前线程所处的情况
  • 关与后台线程:JVM会在一个进程的所有非后台线程结束后,才会结束运行

4、Thread常用方法

(1)等待一个线程--join()

方法 说明
public void join() 等待线程结束
public void join(long millis) 等待线程结束,最多等 millis 毫秒
public void join(long millis, int nanos) 同理,但可以更高精度

使用join后,两个并发并行的线程随即执行的方式,就变成了有序。

(2)获取当前线程引用

public static Thread CurrentThread();
//返回当前线程对象的引用

(3)休眠当前线程

让当前线程休眠(超时等待)给定时间(毫秒)。因为线程的调度是不可控的,这个方法只能保证实际休眠时间大于等于参数设置的休眠时间。

方法 说明
public static void sleep(long millis) throws InterruptedException 休眠当前线程 millis 毫秒

使用场景:进行程序的调试;控制多个线程的执行顺序。

(4)中断线程

方法 说明
public void interrupt() 中断对象关联的线程,如果线程正在阻塞,则以异常方式通知,否则设置中断标志位为true。
public static boolean interrupt() 判断当前线程的中断标志位是否设置,调用后清除标志位(会重置中断标志位)
public static boolean isInterrupt() 判断对象关联的线程标志位是否设置,调用后不清除标志位

【注】

  • Java中断,是以中断标志位的方式执行的;
  • interrupt是发起中断的动作,但线程是否中断,有代码是否判断中断标志位来决定;
  • 线程处于某些等待/超时等待的状态(会显式的抛InterruptException异常),都是允许被中断的,中断的方式是:(1)抛异常来进行中断(2)抛异常后,会重置中断标志位(默认false)

三、多线程(内存的使用)

Java进程的内存:栈、堆、方法区、程序计数器。

猜你喜欢

转载自blog.csdn.net/weixin_54342360/article/details/124450167
今日推荐