【java高级】一: 多线程

这篇博客详细讲解了Java中的多线程概念,包括进程与线程的区别,线程的创建和使用,线程同步机制,如synchronized关键字的应用,线程安全的单例模式,以及线程的死锁问题和JDK 5.0新增的Callable接口和线程池。通过实例分析和代码演示,帮助读者理解多线程编程的关键点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

01、基本概念:程序、进程、线程

1.1 进程与线程

 ​

02 线程的创建和使用

2.1 Thread 类

2.2 API中创建线程的两种方式

2.2.1 方式一 继承Thread类

2.2.2 练习

2.2.3 Thread类中常用方法

2.2.4 线程的调度

 2.2.5 实现Runnable 接口

2.2.6 两种方式的对比

 03 线程的生命周期

04 线程的同步

4.1 理解线程的安全问题

4.2 Java中同步机制解决线程安全问题

4.2.1 同步代码块(synchronized()

4.2.2 同步代码块解决实现Runnable接口中的安全问题

4.2.3 同步代码块解决继承Thread类中的安全问题

4.2.4 同步方法

 4.2.5 使用同步方法解决实现Runnable接口的线程安全问题

4.2.6 使用同步方法解决继承Thread类的线程安全问题

 4.2.7 关于同步方法的总结:

4.3 线程安全的单例模式之懒汉式

05 线程的死锁问题

 06解决线程安全问题方法三:lock锁

 07 线程的通信

 7.1 sleep()和wait()的异同

 7.2 经典例题

 08 JDK 5.0 新增的创建线程的方式

8.1 实现Callable接口

8.2 线程池


01、基本概念:程序、进程、线程

  • 程序(program):为完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象。
  • 进程(process):程序的一次执行过程,或是正在运行的一个程序。是一个动态的过程:有它自身的产生、存在和消亡的过程。——生命周期
    • 如:运行中的QQ,运行中的MP3播放器程序是静态的,进程是动态的
  • 进程作为资源分配的单位,系统在运行时会为每个进程分配不同的内存区域
  • 线程(thread),进程可进一步细化为线程,是一个程序内部的一条执行路径
    • 若一个进程同一时间并行执行多个线程,就是支持多线程的。
    • 线程是调度和执行的单位,每个线程拥有独立的运行栈和程序计数器(pc),线程切换的开销小。
    • 一个进程中的多个线程共享相同的内存单元/内存地址空间—》它们从同一堆中分配对象,可以访问相同的变量和对象。这就使得线程间通信更简便、高效。但多个线程操作共享的系统资源可能就会带来安全的隐患

1.1 进程与线程

 

 单核CPU与多核CPU

单核CPU,其实是一种假的多线程因为在一个时间单元内,也只能执行一个线程的任务。例如:虽然有多车道,但是收费站只有一个工作人员在收费,只有收了费才能通过,那么CPU就好比收费人员。如果有某个人不想交钱,那么收费人员可以把他“挂起”(晾着他,等他想通了,准备好了钱,再去收费)。但是因为CPU时间单元特别短,因此感觉不出来
如果是多核的话,才能更好的发挥多线程的效率。(现在的服务器都是多核的)
一个Java应用程序java.exe,其实至少有三个线程:main()主线程,gc()垃圾回收线程,异常处理线程。当然如果发生异常,会影响主线程。

并行与并发

  • 并行:多个CPU同时执行多个任务。比如:多个人同时做不同的事。
  • 并发:一个CPU(采用时间片)同时执行多个任务。比如:秒杀、多个人做同一件事。

多线程的优点

  1. 提高应用程序的响应。对图形化界面更有意义,可增强用户体验。
  2. 提高计算机系统CPU的利用率
  3. 改善程序结构。将既长又复杂的进程分为多个线程,独立运行,利于理解和修改

 什么时候需要多线程

  • 程序需要同时执行两个或多个任务。
  • 程序需要实现一些需要等待的任务时,如用户输入、文件读写操作、网络操作、搜索等。
  • 需要一些后台运行的程序时。

02 线程的创建和使用

Java语言的JVM允许程序运行多个线程,它通过java.lang.Thread类来体现。(java支持多线程)

Thread类的特性

  • 每个线程都是通过某个特定Thread对象的run()方法来完成操作的,经常把run()方法的主体称为线程体
  • 通过该Thread对象的start()方法来启动这个线程,而非直接调用run()

2.1 Thread 类

构造器

Thread():创建新的Thread对象
Thread(String threadname):创建线程并指定线程实例名
Thread(Runnabletarget):指定创建线程的目标对象,它实现了Runnable接口中的run方法
Thread(Runnable target, String name):创建新的Thread对象
 

2.2 API中创建线程的两种方式

2.2.1 方式一 继承Thread类

  • 定义子类继承 Thread 类。
  • 子类中重写 Thread 类中的 run 方法。
  • 创建 Thread 子类对象,即创建了线程对象。
  • 调用线程对象 start 方法:启动线程,调用 run 方法 。
class MyThread extends Thread{
    //重写Thread类的run(),需要这个线程做的事
    @Override
    public void run() {
        for(int i = 1;i < 100;i++){
            if(i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + i);  // 获取线程
            }
        }
    }
}

public class ThreadTest {
    public static void main(String[] args) {
        //3.创建Thread类的子对象
        MyThread t1 = new MyThread();

        //4.通过此对象调用start():①启动当前线程 ②JVM调用当前线程的run()
        t1.start();

        //如下操作仍在main线程中执行的
        for(int i = 1;i < 100;i++){
            if(i % 2 == 0){
                System.out.println(i + "***main()***");
            }
        }
    }
}

 注意

2.2.2 练习

/**
 * 练习:创建两个分线程,其中一个遍历100以内的偶数,另一个遍历100以内的奇数

创建两个Thread子类,分别重写run()
 */
public class ThreadDemo {
    public static void main(String[] args) {
        MyThread m1 = new MyThread();
        m1.start();

        MyThread2 m2 = new MyThread2();
        m2.start();
    }
}
class MyThread extends Thread{
    @Override
    public void run() {
        for(int i = 0;i < 100;i++){
            if(i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}

class MyThread2 extends Thread{
    @Override
    public void run() {
        for(int i = 0;i < 100;i++){
            if(i % 2 != 0){
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
        }
    }
}

 写法二: 匿名子类的方式

/**
 * 练习:创建两个分线程,其中一个遍历100以内的偶数,另一个遍历100以内的奇数
 */
public class ThreadDemo {
    public static void main(String[] args) {

        //创建Thread类的匿名子类的方式
        new Thread(){
            @Override
            public void run() {
                for(int i = 0;i < 100;i++){
                    if(i % 2 == 0){
                        System.out.println(Thread.currentThread().getName() + ":" + i);
                    }
                }
            }
        }.start();

        new Thread(){
            @Override
            public void run() {
                for(int i = 0;i < 100;i++){
                    if(i % 2 != 0){
                        System.out.println(Thread.currentThread().getName() + ":" + i);
                    }
                }
            }
        }.start();
    }
}

2.2.3 Thread类中常用方法

* 测试Thread类的常用方法
 * 1.start():启动当前线程,执行当前线程的run()
 * 2.run():通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中
 * 3.currentThread(): 静态方法,返回当前代码执行的线程
 * 4.getName():获取当前线程的名字
 * 5.setName():设置当前线程的名字
 * 6.yield(): 释放当前CPU的执行权
 * 7.join():在线程a中调用线程b的join(),此时线程a就进入阻塞状态,直到线程b完全执行完以后,线程a才 结束阻塞状态。
 * 8.stop():已过时。当执行此方法时,强制结束当前线程。
 * 9.sleep(long millitime):让当前线程“睡眠”指定时间的millitime毫秒)。在指定的millitime毫秒时间内,当前线程是阻塞状态的。
 * 10.isAlive():返回boolean,判断线程是否还活着
 */

class HelloThread extends Thread{
    @Override
    public void run() {
        for(int i = 0;i < 100; i++){

            try {
                sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if(i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }
//            if(i % 20 == 0){
//                yield();  //释放当前线程的执行权,但不一定会释放成功
//            }
        }
    }

    public HelloThread(String name){
        super(name);
    }
}

public class ThreadModeTest {
    public static void main(String[] args) {
        HelloThread h1 = new HelloThread("Thread : 1");

//        h1.setName("线程一");

        h1.start();

        //给主线程命名
        Thread.currentThread().setName("主线程");

        for(int i = 0;i < 100; i++){
            if(i % 2 == 0){
                System.out.println(Thread.currentThread().getName() + ":" + i);
            }

            if(i == 20){
                try {
                    h1.join();  // 线程主线程进入阻塞状态,直到h1执行完毕
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

        System.out.println(h1.isAlive());
    }
}

2.2.4 线程的调度

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值