Java线程基础

 一、基本概念

    1、三高:高可用、高性能、高并发、

    2、多线程:同一时间执行多个任务

    3、程序、进程、线程:

            (1)程序:静态的代码

            (2)进程:CPU调度的代码(动态概念)

            (3)线程:一个进程中开辟多条路径

    4、进程和线程的区别:

(1)根本区别:进程:作为资源分配的单位;线程:CPU调度和执行的单位

(2)开销:进程:每个进程都有独立的代码和数据空间(进程上下文),进程间的切换会有较大的开销;线程:可以看做是轻量级进程,同一类线程共享代码和数据空间,每个线程有独立的运行栈和程序计数器(PC),线程切换的开销小。

(3)所处环境:进程:在操作系统中可以同时运行多个任务;线程:在同一应用程序中有多个顺序流同时执行。

(4)分配内存:进程:系统运行时会给每一个进程分配不同的内存区域;线程:除了CPU之外,不会为线程分配内存,(线程所使用的资源是它所属的进程的资源),线程只能共享资源。

(5)包含关系:线程是进程的一部分,一个进程如果只有一条线程,那么该进程被称为单线程进程,否则叫多线程进程。

    5、核心概念:

》线程才是独立执行的路径;

》程序运行时即使没有自己创建多线程,后台也会存在多线程。例如gc(垃圾回收)线程;

》一个线程中的多个进程,由调度器统一安排调度,调度器是与操作系统紧密相关的,先后顺序无法认为干预;

》操作同一份资源(共享资源)时,会存在资源抢夺,需要加入并发控制;

》每个线程有自己的工作空间,通过工作空间与主内存交互,线程如果操作不当会造成数据不一致

二、线程创建方式

    1、创建线程

(1)继承Thread类,重写run方法,创建子类对象并调用子类start()方法;

        run方法内是线程需要执行的动作,start方法的作用是将线程创建好丢给CPU,等待CPU的调度。切记:start方法只是告知CPU当前线程已进入就绪态,不会立即执行该线程

        如果直接调用子类的run方法,效果就是普通方法的调用,必须顺序执行,不会出现多线程。

(2)实现Runnable接口,重写run方法,创建实现类对象并丢给Thread类,调用Thread类的Start方法;推荐使用该方法,避免单继承的局限性。

        因为Runnable接口没有start方法,不能丢给CPU,所以需要new Thread(new PrimeRun(11)).start();

        run方法不允许抛出异常。没有返回值

(3)实现Callable接口,重写call方法(juc);

         call方法允许抛出异常。有返回值

        使用方法:

        1.创建目标对象:(即实现Callable接口的对象)

        2.创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1);

        3.提交执行:Future result = ser.submit(cd1);

        4.获取结果:boolean r1 = result.get();

        5.关闭服务:ser.shutdownNow();

        Java线程基础_第1张图片

 

三、静态代理

    1、真实角色和代理角色实现同一个代理接口

    2、代理接口定义代理方法

    3、真实角色实现代理方法

    4、代理角色声明代理接口,在实现代理方法中调用真实角色重写的方法(多态)

    例:Java线程基础_第2张图片

 

四、lambda表达式 

    使用要求:

1、目的是简化匿名内部类的使用,避免匿名内部类过多,实质是函数式编程;

2、要求传入的参数是一个接口,并且该接口内部只有一个抽象方法;

3、注意:一定要指定接口名,要不然系统不知道到底推导哪个;

例:

Java线程基础_第3张图片

五、线程状态

Java线程基础_第4张图片

 

注意:运行状态被阻塞结束后不能马上进入运行态;线程死亡后不能复活(不能继续执行)

Java线程基础_第5张图片

 

线程有自己的工作空间,从主内存拷贝数据到工作空间然后执行

到达就绪态的四种方式:调用start()方法(线程刚刚调用);阻塞状态解除;调用yield方法;jvm主动切换到其他线程

到达阻塞态的四种方式:sleep;wait;join;调用其他资源(IO操作)

 六、线程的基本操作

    1、停止线程

一般停止线程主要有两种方式:线程自动执行完毕或认为停止线程调用

不建议使用stop()方法和distory()方法

可以在run方法里面加一个标识去人为控制线程执行

例:

package com.zzu.threadmethod;
public class Terminal implements Runnable{
       boolean flag = true;
       @Override
       public void run() {
              for(int i=0;i<100;i++) {
                     if(!flag) {
                           break;
                     }
                     System.out.println("线程第"+i+"次执行");
              }
       }
       public void terminal() {
              flag = false;
       }
       public static void main(String[] args) {
              Terminal terminal = new Terminal();
              new Thread(terminal).start();
              for(int i=0;i<100;i++){
                     if(i==50) {
                           terminal.terminal();
                           System.out.println("线程结束");
                     }
                     System.out.println("main第"+i+"次运行");
              }
       }
}

    2、sleep方法

sleep(时间)指定当前线程阻塞的毫秒数

sleep存在异常InterruptedException

sleep时间到达后线程进入就绪态

sleep可以模拟网络延时、倒计时等

sleep每个对象都有一个锁,sleep不会释放锁(不会释放资源,针对wait来说)

用法:Thread.sleep(1000);哪个线程体执行该方法,该线程体阻塞

一般用来模拟网络延时或者倒计时

    3、yield

礼让线程,让当前执行线程从执行态进入就绪态,让CPU重新调度

调用方法:Thread.yield();

主要作用:避免一个线程占用CPU时间过久

    4、join

join合并线程,待此线程执行完成,再执行其他线程,其他线程阻塞

相当于插队

使用方法: 在被插队的线程中新建插队的线程对象。并执行

package com.zzu.threadmethod;
public class Join {
       public static void main(String[] args) {
              new Thread(new FThread()).start();//创建父线程
       }
}
class FThread implements Runnable{
       @Override
       public void run() {
              SThread s = new SThread();
              Thread a = new Thread(s);
              a.start();//子线程创建
              try {
                     for (int i = 0; i <10; i++) {
                           System.out.println("fatherThread第"+i+"次执行");
                           if(i==3) {
                                  a.join();//插队
                           }
                           Thread.sleep(1000);
                     }
              } catch (InterruptedException e) {
                     e.printStackTrace();
              }
       }
}
class SThread implements Runnable{
       @Override
       public void run() {
              for (int i = 0; i < 10; i++) {
                     System.out.println("------->sonThread第"+i+"次执行");
                     try {
                           Thread.sleep(1000);
                     } catch (InterruptedException e) {
                           e.printStackTrace();
                     }
              }
       }
}

七、线程标准状态

    Thread.State:

NEW:尚未启动的线程

RUNNABLE:在Java虚拟机中执行的线程

BLOCKED:被阻塞等待监视器锁定的线程

WAITING:在等待另一个线程执行特定动作的线程

TIMED_WAITING:等待另一个线程执行动作达到指定时间的线程

TERMINATED:已退出的线程

package com.zzu.threadmethod;
public class AllState implements Runnable{
       @Override
       public void run() {
              for (int i = 0; i < 3; i++) {
                     System.out.println();
                     try {
                           Thread.sleep(100);
                     } catch (InterruptedException e) {
                           e.printStackTrace();
                     }
              }
       }
       public static void main(String[] args) {
              Thread t = new Thread(new AllState());
              System.out.println(t.getState());
              t.start();
              for(;t.getState()!=Thread.State.TERMINATED;) {
                     System.out.println(t.getState());
                     try {
                           Thread.sleep(50);
                     } catch (InterruptedException e) {
                           e.printStackTrace();
                     }
              }
              System.out.println(t.getState());
       }
}

八、优先级

    1、priority优先级范围1-10,优先级越高被调用的可能性越大(但不是绝对);

    2、priority的三个基本常量:MIN_PRIORITY=1;MAX_PRIORITY=10;NORM_PRIORITY=5;

    3、获取当前线程的优先级:Thread.currentThread().getPriority();

    4、设置线程优先级:t.setPriority(1-10);注意,设置优先级必须在线程启动前

九、线程分类

    1、线程分为用户线程和守护线程(Daemon)

    2、虚拟机必须确保用户线程执行完毕

    3、虚拟机不用等待守护线程执行完毕

    4、守护线程:后台记录操作日志、监控内存使用等

package com.zzu.threadmethod;
public class DeamonTest implements Runnable{
       public static void main(String[] args) {
              Thread a = new Thread(new DeamonTest());
              Thread b = new Thread(new DeamonThread());
              b.setDaemon(true);
              a.start();
              b.start();
       }
       @Override
       public void run() {
              for(int i=0;i<5;i++) {
                     System.out.println("用户线程---------");
              }
       }
}
class DeamonThread implements Runnable{
       @Override
       public void run() {
              while(true) {
                     System.out.println("守护线程---------");
              }
       }   
}

十、其他方法

    1、currentThread()//当前线程

    2、setName()、getName()//设置代理姓名

    3、isAlive()//线程是否还活着

你可能感兴趣的:(JAVA面试,java,开发语言,后端)