多线程学习一

一、简介

程序:为了解决某个问题或执行某个操作编写一系列指令的集合program

进程:在操作系统中独立运行的程序,每运行一个应用程序就表示启动了一个进程 process

线程:是进程内部的一个执行单元,用来执行应用程序中的一个功能 thread

多线程:在一个应用程序中可以同时执行多个功能,例如迅雷中同时执行多个下载任务就是多线程

特性:

  • 一个进程中可以包含多个线程,且至少要有一个线程
  • 一个线程必须属于某个进程,进程是线程的容器
  • 一个进程中的多个线程共享该进程的所有资源

二、进程与线程的区别

区别进程线程
根本区别作为资源分配的单位调度和执行的单位
开销每个进程都有独立的代码和数据空间,进程间的切换会有较大的开销线程可以看做轻量级的进程同一线程共享代码和数据空间,每个线程都有自己独立的运行栈和程序计数器,线程切换的开销小
所处环境在操作系统中能运行多个任务(程序)在同一个应用程序中有多个顺序流同时执行
分配内存系统在运行的时候会为每个进程分配不同的内存区域除CPU外,不会为线程分配内存(线程所使的资源是它所属进程的资源)线程组只能共享资源
包含关系没有线程的进程是可以看做成单线程的,如果一个进程中有多个线程,则执行过程不是一条线的,而是多条线(线程)共同完成的。线程是进程的一部分,所以线程有时候被称为轻权进程或轻量级进程

三、常见创建线程的方式

3.1 方式一,继承Thread类

第一步:定义一个类并继承Thread类,并重写run方法

public class MyThread extends Thread{
    @Override
    public void run() {
        //代码编写区
        for (int i = 0;i<5;i++){
            System.out.print(i+" ");
        }
        System.out.println();
    }
}

第二步:创建该类的实例,相当于创建了一个线程

public static void main(String[] args) {
        //创建一个线程实例
        MyThread myThread = new MyThread();

    }

第三步:调用start()方法,即开始启动线程

public static void main(String[] args) {
        //创建一个线程实例
        MyThread myThread = new MyThread();
        myThread.start();
    }

在这里插入图片描述

3.2 方式二,实现Runable接口

第一步:定义一个类,去实现Runable接口,并重写run方法

public class MyRunable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.print(i + " ");
        }
        System.out.println();
    }
}

第二步:创建刚定义那个类的实例

public static void main(String[] args) {
        //创建MyRunable实例
        MyRunable myRunable = new MyRunable();
    }

第三步:创建一个Thread类实例,并把创建好的MyRunable对象传入该实例中

 public static void main(String[] args) {
        //创建MyRunable实例
        MyRunable myRunable = new MyRunable();
        //创建一个Thread实例,并把上面创建好的对象传入其中
        Thread thread = new Thread(myRunable);
    }

第四步:调用线程thread的start()方法,表示开始启动线程

public static void main(String[] args) {
        //创建MyRunable实例
        MyRunable myRunable = new MyRunable();
        //创建一个Thread实例,并把上面创建好的对象传入其中
        Thread thread = new Thread(myRunable);
        //启动线程
        thread.start();
    }

在这里插入图片描述

3.3 两种方式的对比

继承Thread类 :

  • 线程执行的代码放在Thread类的子类的run方法中

  • 无法再继承其他类

    买票案例演示:

    public class Ticket extends Thread{
        private int ticket = 5;
        @Override
        public void run() {
            for (int i = 0;i<ticket;i++){
                System.out.print("已卖出第"+(i+1) + "张票" + "");
            }
        }
    }
    
    public static void main(String[] args) {
           new Ticket().start();
           new Ticket().start();
           new Ticket().start();
           new Ticket().start();
        }
    

    运行代码后,会发现卖出了20张票,这表示每个线程都是独立的,并没有共享要卖的这5张票,这是不符合需求的

实现Runnable接口(推荐使用):

  • 线程执行的代码放在Runnable接口的实现类的run方法中

  • 可以继承其他类,避免单继承的局限性

  • 适合多个相同程序代码的线程去处理同一个资源

  • 增强程序的健壮性

    卖票案例演示:

    public class Ticket implements Runnable{
        private int ticket = 5;
        @Override
        public void run() {
            for (int i = 0;i<100;i++){
                if (ticket > 0){
                    System.out.println( "正在出售第" + (ticket--) + "张票");
                }
            }
        }
    }
    
    public static void main(String[] args) {
            Ticket ticket = new Ticket();
            new Thread(ticket).start();
            new Thread(ticket).start();
            new Thread(ticket).start();
            new Thread(ticket).start();
        }
    

    结果发现,不多也不少正好卖完了5张票,表示使用实现Runnable接口的方式是可以数据共享的

四、线程的生命周期

在这里插入图片描述

1.新生状态
    用new关键字建立一个线程后,该线程对象就处亍新生状态。
    处于新生状态的线程有自己的内存空间,通过调用start()方法进入就绪状态。
2.就绪状态
    处于就绪状态线程具备了运行条件,但还没分配到CPU,处于线程就绪队列,等待系统为其分配CPU。 
    当系统选定一个等待执行的线程后,它就会从就绪状态进入执行状态,该动作称为“CPU调度”。
3.运行状态
    在运行状态的线程执行自己的run方法中代码,直到等待某资源而阻塞或完成任务而死亡。
    如果在给定的时间片内没有执行结束,就会被系统给换下来回到等待执行状态。
4.阻塞状态
    处于运行状态的线程在某些情况下,如执行了sleep(睡眠)方法,或等待I/O设备等资源,将让出CPU并暂时停止自己运行,进入阻塞状态。
    在阻塞状态的线程不能进入就绪队列。只有当引起阻塞的原因消除时,如睡眠时间已到,或等待的I/O设备空闲下来,线程便转入就绪状态,重新到就绪队列中排队等待,被系统选中后从原来停止的位置开始继续执行。
5.死亡状态
    死亡状态是线程生命周期中的最后一个阶段。线程死亡的原因有三个,一个是正常运行的线程完成了它的全部工作;另一个是线程被强制性地终止,如通过stop方法来终止一个线程(不推荐使用);三是线程抛出未捕获的异常。

五、线程相关的的常用操作方法

方法名方法描述
public static Thread currentThread()返回目前正在执行的线程
public final String getName()获取线程的名称
public void setName(String name)设置线程的名称
public final int getPriority()获取线程的优先级别
public void setPriority(int newPriority)设置线程的优先级别
public final boolean isAlive()判断此此线程是否存活。
public final void join()调用该方法的线程,会让其它线程处于阻塞状态,该线程执行完毕后,其它线程再执行
public static void sleep(long millis)设置当前正在执行的线程休眠millis秒,线程处于阻塞状态
public static void yield()让当前正在执行的线程暂停一次,允许其他线程执行,不阻塞,线程进入就绪状态,如果没有其他等待执行的线程,这个时候当前线程就会马上恢复执行
public boolean isDaemon()测试此线程是否为守护线程
public void interrupt()中断此线程
5.1 currentThread() 返回目前正在执行的线程的信息
public static void main(String[] args) {
        Thread thread = Thread.currentThread();
        System.out.println(thread);
    }
    
结果:Thread[main,5,main] //第一main表示线程的名称,5表示线程的优先级别,第二个main表示该线程所属的线程组
5.2 getName() 获取线程的名称
public class MyRunable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.print(i + " ");
        }
        System.out.println();
    }
}
public static void main(String[] args) {
        MyRunable myRunable = new MyRunable();
        System.out.println("线程名:" + new Thread(myRunable).getName());
        Thread thread = Thread.currentThread();
        System.out.println("线程名:" + thread.getName());
    }

在这里插入图片描述

5.3 setName(String name) 设置线程的名称
public static void main(String[] args) {
        MyRunable myRunable = new MyRunable();//实现了Runable接口
        Thread thread = new Thread(myRunable);
        System.out.println("原线程名:" + thread.getName());
        thread.setName("th-001");
        System.out.println("设置后的线程名:" + thread.getName());
    }

在这里插入图片描述

5.4 getPriority() 获取线程的优先级别,在java中线程优先级分为1~10,数值越大,优先级越高,默认为5
public static void main(String[] args) {
        MyRunable myRunable = new MyRunable();//实现了Runable接口
        Thread thread = new Thread(myRunable);
        System.out.println("此线程的优先级别为:" + thread.getPriority());
        Thread main = Thread.currentThread();
        System.out.println("main线程的优先级别为:" + main.getPriority());
    }

在这里插入图片描述

5.5 setPriority(int newPriority) 设置线程的优先级
public static void main(String[] args) {
        MyRunable myRunable = new MyRunable();//实现了Runable接口
        Thread thread = new Thread(myRunable);
        thread.setPriority(8);
        System.out.println("此线程的优先级别为:" + thread.getPriority());
        Thread main = Thread.currentThread();
        System.out.println("main线程的优先级别为:" + main.getPriority());
    }

在这里插入图片描述

5.6 isAlive() 判断线程是否存活,true表示还活着,false表示该线程已死亡
public static void main(String[] args) {
        MyRunable myRunable = new MyRunable();
        Thread thread =new Thread(myRunable);
        System.out.println(thread.getName()+":" + thread.isAlive());
        Thread main = Thread.currentThread();
        System.out.println(main.getName() + ":"+main.isAlive());
    }

在这里插入图片描述

5.7 join() 调用该方法的线程,会让其它线程处于阻塞状态,该线程执行完毕后,其它线程再执行
public class MyRunable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName()+":" + i);
        }
    }
}
//没有线程调用join()方法之前
public static void main(String[] args)  {

        MyRunable myRunable = new MyRunable();
        Thread thread = new Thread(myRunable);
        thread.start();
        for (int i = 0;i<5;i++){
            System.out.println(Thread.currentThread().getName()+":" + i);
        }

    }

在这里插入图片描述

 public static void main(String[] args) throws InterruptedException {
        MyRunable myRunable = new MyRunable();
        Thread thread = new Thread(myRunable);
        thread.start();
        thread.join();//调用join方法
        for (int i = 0;i<5;i++){
            System.out.println(Thread.currentThread().getName()+":" + i);
        }
    }

在这里插入图片描述

5.8 sleep(long millis) 设置当前正在执行的线程休眠millis秒,线程处于阻塞状态,单位为毫秒
public static void main(String[] args) throws InterruptedException {
        for (int i = 0;i<5;i++){
            if (i == 3){
                long start = System.currentTimeMillis();
                Thread.sleep(3000);
                long end = System.currentTimeMillis();
                System.out.println("睡眠了多久: "+(end-start)+"毫秒");
            }
            System.out.println(i);
        }
    }

在这里插入图片描述

5.9 yield() 让当前正在执行的线程暂停一次,允许其他线程执行,不阻塞,线程进入就绪状态,如果没有其他等待执行的线程,这个时候当前线程就会马上恢复执行
public class MyThread extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 15; i++) {
            System.out.println(this.getName()+":" + i);
            if(i==7){
                this.yield();
            }
        }
    }
}

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

        MyThread myThread = new MyThread();
        MyThread myThread2 = new MyThread();
        myThread.start();
        myThread2.start();

    }

在这里插入图片描述

5.10 isDaemon() 测试此线程是否为守护线程
 public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(new MyRunable());
        boolean daemon = thread.isDaemon();
        System.out.println(daemon);
        System.out.println(Thread.currentThread().isDaemon());
    }

在这里插入图片描述

5.11 interrupt() 中断此线程,线程的中断是由本身线程决定的,其它线程无法干预
public class MyRunable implements Runnable {
    @Override
    public void run() {
        for (int i = 1;i<10;i++){
            System.out.println(Thread.currentThread().getName()+":"+i);
            try {
                Thread.sleep(1500);
            } catch (InterruptedException e) {
                System.out.println("发现中断标记,结束线程");
                return;
            }
        }
    }
}
public static void main(String[] args) throws InterruptedException {
        MyRunable myRunable = new MyRunable();
        Thread myThread = new Thread(myRunable, "lisi");
        myThread.start();
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + i);
            Thread.sleep(1000);
        }
        myThread.interrupt();
    }
            }
        }
    }
}
public static void main(String[] args) throws InterruptedException {
        MyRunable myRunable = new MyRunable();
        Thread myThread = new Thread(myRunable, "lisi");
        myThread.start();
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + ":" + i);
            Thread.sleep(1000);
        }
        myThread.interrupt();
    }

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值