回顾Java知识点,面试题汇总Day7(持续更新)

一、多线程

使用多线程可以让程序充分利用CPU的资源,提高CPU的使用效率,从而解决高并发所带来的负载均衡问题。

优点:

  • 资源得到更合理的利用
  • 程序设计更加简洁
  • 程序响应速度更快,运行效率更高

缺点:

  • 需要更多的内存空间来支持多线程
  • 多线程并发访问的情况可能会影响数据的准确性
  • 数据被多线程共享,可能会出现死锁的情况

应该将程序设计更加合理有效,避免多线程的缺点,充分发挥多线程的优点,从而提高程序的性能。

1. 进程和线程

什么是进程?

进程就是计算机正在运行的一个独立的应用程序,进程是一个动态的概念。

什么是线程?

线程是组成进程的基本单位,一个进程种包含一个或多个线程,线程可以完成特定的功能。

进程和线程都是应用程序在执行过程种的概念,如果应用程序没有执行,就不存在进程和线程。

应用程序是静态的概念,进程和线程是动态的,有创建就有销毁,存在是暂时的。

2. 进程和线程的区别?

进程在运行时有独立的内存空间,每个进程占用的内存都是独立的,互不干扰。

多个线程是共享内存空间的,但每个线程的执行是相对独立的,只不过共用内存空间。

线程必须依赖于进程才能执行,单独的线程是无法执行的,由进程来控制多个线程的执行。

多线程:一个进程中,多个线程同时执行。

单核CPU的情况下,多线程并不是真正的同时执行,而是多个线程交替占用CPU,执行自己的业务。

因为程序执行速度太快,看起来是在同时执行。

java 复制代码
public class ThreadTest {
    public static void main(String[] args) {
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                System.out.println("++++++" + i);
            }
        }).start();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                System.out.println(i + "========");
            }
        }).start();
    }
}

多核CPU的情况下,线程才是真正地同时执行。

3.Java中线程的使用

3.1 继承Thread类

  • Thread类是Java提供的线程的父类
  • 实现程序的扩展,基于JDK基础类开发者可以扩展出其他的相关类。
  • 对修改封闭(不能改源码),对扩展开放(自定义类,通过继承的形式融入到JDK中)
  • 线程一定跟任务绑定,一个线程必须要执行一个任务,一个空的线程没有意义,一个空的任务也没有意义,一定是线程+任务绑定在一起。

Thread类是JDK线程父类,Runnable接口时JDK定义任务的接口,任务的具体实现写在run方法中

  • 创建Thread对象的时候,从外部传入一个Runnable对象(创建线程的时候,需要绑定一个任务)
  • 当线程执行的时候,会调用线程的run方法
  • 如果创建线程对象的时候,传入了任务,则会执行任务,否则线程什么都不做。

使用线程

1.创建线程对象

2.调用线程对象的start方法来启动线程

线程首先需要去争夺CPU资源,当拿到资源之后才能执行任务

run方法和start方法的区别?

main作为程序入口,本质上也是一个线程。

使用run方法时,定义的线程对象会被当成普通对象进行处理,main线程使用CPU进行执行。此时只有一个线程:mian

使用start方法时,定义的线程对象就是一个线程,并且使用CPU进行执行,此时有两个线程:main和thread

java 复制代码
package com.thread;

public class MyThread extends Thread{
    @Override
    public void run(){
        for (int i = 0; i < 20; i++) {
            System.out.println(i+"=========");
        }
    }
}
java 复制代码
package com.thread;

public class Test {
    public static void main(String[] args) {
        //创建线程对象
        MyThread thread = new MyThread();
        //启动线程
        thread.start();
    }
}

3.2 实现Runnable接口

第一种形式线程和任务的耦合度过高,不利于程序的扩展,所以开发中不推荐使用

实现解耦合

java 复制代码
package com.thread;

public class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(i+"+++++++++++++");
        }
    }
}
java 复制代码
package com.thread;

public class Test {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start();
    }
}

把任务和线程组装起来。

二、线程的状态

1.5种状态

5种状态,在特定的情况下,线程可以在不同的状态之间切换

  • 创建状态:实例化了一个新的线程对象,还未启动;
  • 就绪状态:创建好的线程对象调用了start()方法完成启动,进入线程池等待抢占CPU资源;
  • 运行状态:线程对象获取了CPU资源,在规定的时间内执行任务
  • 阻塞状态:正在运行的线程暂停执行任务,释放所占用的CPU资源
  • 终止状态:线程运行完毕或因为异常导致线程终止运行

2.lambda表达式

函数式编程,将方法的实现作为参数进行传递,可以简化代码的开发

1、通过实现Runnable接口的形式来完成线程的使用

java 复制代码
package com.thread;

public class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(i+"+++++++++++++");
        }
    }
}
java 复制代码
package com.thread;

public class Test {
    public static void main(String[] args) {
        MyRunnable myRunnable = new MyRunnable();
        Thread thread = new Thread(myRunnable);
        thread.start();
   }
}

2.使用内部类对代码进行简化

java 复制代码
package com.thread;

public class Test {
    public static void main(String[] args) {
        Runnable1 myRunnable = new Runnable1();
        Thread thread = new Thread(myRunnable);
        thread.start();
    }

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

3.使用匿名内部类进行简化

java 复制代码
package com.thread;

public class Test {
    public static void main(String[] args) {
        Runnable myRunnable = new Runnable() {

            @Override
            public void run() {
                for (int i = 0; i < 100; i++) {
                    System.out.println(i + "+++++++++++++");
                }
            }
        };
        Thread thread = new Thread(myRunnable);
        thread.start();
    }
}

new后面的就是类名。此时Runnable表示实现的接口

4.使用lambda表达式

Thread thread = new Thread(()->{ });

java 复制代码
package com.thread;

public class Test {
    public static void main(String[] args) {
        new Thread(()->{
            for (int i = 0; i < 100; i++) {
                System.out.println(i+"+++++++++++++");
            }
        }).start();
    }
}

将接口作为参数传递的场景下,可以使用lambda进行简化

java 复制代码
package com.thread;

public interface MyRunnable1 {
    public void test();
}
java 复制代码
package com.thread;

public class MyTest {
    public void test(MyRunnable1 myRunnable1){
        myRunnable1.test();
    }
}
java 复制代码
package com.thread;

public class Test1 {
    public static void main(String[] args) {
        MyTest myTest = new MyTest();
        myTest.test(()->{
            System.out.println(111);
        });
    }
}

接口中只能有一个方法,多个方法会报错。因为无法判断具体指向的方法。

三、线程休眠

休眠是指让当前线程暂停执行,从运行状态进入阻塞状态,从而将CPU资源让给其他线程的一种调度方式,通过sleep方法来实现。

java 复制代码
public static native void sleep(long millis) throws InterruptedException;
java 复制代码
package com.thread;

public class Test {
    public static void main(String[] args) {
        Thread thread = new Thread(()->{
            for (int i = 0; i < 100; i++) {
                if (i == 5){
                    try {
                        Thread.sleep(1000);//1秒
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
                System.out.println(i+"+++++++++++++");
            }
        });
        thread.start();
    }
}

lambda表达式只能调用静态方法。

1.多线程的场景中,调用sleep是让哪个休眠?

不是谁调用sleep就让谁休眠,而是看在哪个线程中调用sleep方法就让哪个线程休眠,和调用者无关。

java 复制代码
package com.thread;

public class Test2 {
    public static void main(String[] args) {
        //子线程
        Thread thread = new Thread(()->{
            for (int i = 0; i < 100; i++) {
                System.out.println(i + "===================");
            }
        });
        thread.start();

        try {
            thread.sleep(2000);  //子线程调用,但是代码块在main方法中,休眠的是主线程
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        //主线程
        for (int i = 0; i < 100; i++) {
            System.out.println("++++++++++++++++++++++++++++++mian" + i);
        }
    }
}

判断方法在哪里面,谁休眠。

四、线程合并

合并是指将指定的某个线程加入到当前线程种,合并为一个线程。

由两个线程交替执行变成一个线程中的两个子线程顺序执行,一个线程执行完毕后再来执行第二个线程,通过join方法来实现合并。

谁调用join方法,谁被合并,谁先执行

java 复制代码
package com.thread;

public class JoinRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 30; i++) {
            System.out.println(i+ "-----------------JoinRunnable");
        }
    }
}
java 复制代码
package com.thread;

public class Test2 {
    public static void main(String[] args) {
        JoinRunnable joinRunnable = new JoinRunnable();
        Thread thread = new Thread(joinRunnable);
        thread.start();

        for (int i = 0; i < 50; i++) {
            if(i == 10){
                try {
                    thread.join();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println(i + "这是mian线程");

        }
    }

}

join()方法存在重载

join(long mills)

1.join()和join(long mills)的区别?

通过join进行合并,则合并的线程会一直占用CPU资源,知道自己的任务结束才会释放CPU,另外一个线程才能执行。

通过join(long mills)进行合并,则合并进来的线程会根据mills时间来占用CPU资源,时间到了之后无论线程是否执行完毕,都会释放CPU资源,回到两个线程争夺CPU资源的情况。

相关推荐
努力努力再努力wz1 小时前
【Qt入门系列】深入理解信号与槽:从事件响应到自定义信号机制
c语言·开发语言·数据结构·数据库·c++·qt·mysql
在角落发呆1 小时前
DTU 数据转发服务器:工业物联网的隐形桥梁
开发语言·php
Sakuyu434681 小时前
C语言基础--基本数据类型
c语言·开发语言
在坚持一下我可没意见1 小时前
Python 修仙修炼录 05:循环神通,省去无用苦修
开发语言·python·面试·入门·循环·复习
云烟成雨TD1 小时前
Spring AI Alibaba 1.x 系列【53】Interrupts 中断机制:动态中断
java·人工智能·spring
用户298698530141 小时前
Java 操作 Word 文档:数学公式与符号的插入方法
java·后端
见青..1 小时前
JAVA安全靶场环境搭建
java·web安全·靶场·java安全
一坨阿亮1 小时前
Docker 离线部署
java·spring cloud·docker
techdashen1 小时前
Rust 社区在 4 月做了什么:项目管理月报解读
开发语言·rust·mfc