搜索
首页Javajava教程Java知识点总结之多线程基础

本篇文章给大家带来了关于java的相关知识,其中主要介绍了关于多线程的相关内容,同一时刻,可以执行多个线程。例如:使用迅雷可以同时下载多个文件,下面一起来看一下,希望对大家有帮助。

Java知识点总结之多线程基础

推荐学习:《java视频教程

一、线程相关概念

1、程序:是为完成特定任务、用某种语言编写的一组指令的集合。简单的说:就是我们写的代码

2、进程:是指运行中的程序,比如我们使用QQ,就启动了一个进程,操作系统就会为 该进程分配内存空间。当我们使用迅雷,又启动了一个进程,操作系统将为迅雷分配新的内存空间。

进程是程序的一次执行过程,或是正在运行的一个程序。是动态过程:有它自身的产生、存在和消亡的过程。

3、线程:是进程创建的,是进程的实体,一个进程可以有多个线程,例如使用迅雷下载文件,迅雷相当于进程,下载的文件相当于线程。

4、单线程:同一时刻,只允许执行一个线程

5、多线程:同一时刻,可以执行多个线程。例如:使用迅雷可以同时下载多个文件。

6、并发:同一时刻,多个任务交替进行。单核CPU实现的多任务就是并发。

7、并行:同一时刻,多个任务同时进行。多核CPU可以实现并行,当任务较多时,并发和并行有可能同时发生。

二、线程基本使用

创建线程有两种方法:

1、继承Thread类,重写run方法。

2、实现Runnable接口,重写run方法。

注意:Thread类实现了Runnable接口。

(一) 继承Thread类,重写run方法

public class Thread01 {
    public static void main(String[] args) throws InterruptedException {
        Cat cat = new Cat();
        cat.start();
        System.out.println("主线程" + Thread.currentThread().getName());
        for (int i = 1; i <= 5; i++) {
            System.out.println("主线程i=" + i);
            Thread.sleep(1000);
        }
    }}class Cat extends Thread{
    int times = 0;
    @Override    public void run() {
        while (true) {
            System.out.println("你好" + (++times) + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (times == 5){
                break;
            }
        }
    }}

1、在继承Thread类,重写了run()方法后,在main方法中需要创建对象,并调用start()方法,启动线程。

2、使用start()方法,会调用重写的run()方法。

3、如果main方法中,start()方法后面还有执行语句,并且run()方法中也有执行语句,main线程中会启动一个子线程Thread-0,主线程不会阻塞,主线程与子线程会交替执行。

注意:如果主线程执行完毕,但子线程未执行完,进程不会结束,所有线程执行完毕后,进程自动结束。

4、在主线程中为什么使用start()方法去调用run()方法,而不是直接调用run()方法,因为run()方法是一个普通方法,没有真正启动线程,如果调用run()方法,就会将run()方法执行完毕后,再执行main方法剩余语句,主线程就会阻塞。

所以上面程序都运算结果是:

主线程main
主线程i=1你好1Thread-0主线程i=2你好2Thread-0主线程i=3你好3Thread-0主线程i=4你好4Thread-0主线程i=5你好5Thread-0

(二) 实现Runnable接口,重写run方法

public class Thread02 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        Thread thread = new Thread(dog);
        thread.start();
    }}class Dog implements Runnable{
    @Override    public void run() {
        int count = 0;
        while (true) {
            System.out.println("小狗汪汪叫" + (++count) + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (count == 10){
                break;
            }
        }
    }}

1、因为Runnable接口中没有start()方法,所以需要代理

2、先在main方法中需要创建对象,然后创建一个Thread对象,将之前创建的对象传入Thread,借助Thread,调用start()方法,创建线程。

3、建议使用Runnable,因为实现Runnable接口更加适合多个线程共享一个资源的情况,避免了单继承的限制。

三、线程终止

(一)基本说明

1、当线程执行完任务时会自动退出。

2、也可以使用变量控制run()方法退出终止线程。

(二)操作

1、如果一个线程中的run()方法内部是一个while(true){},即一个无限循环

2、我们可以在线程内部,创建一个boolean属性loop,让loop = true,然后while(loop){}

3、再提供一个setLoop方法,这样就可以在其他类中调用setLoop方法,改变boolean值,来控制线程终止。

(三)代码演示

public class ThreadExit {
    public static void main(String[] args) throws InterruptedException {
        T t = new T();
        t.start();
        Thread.sleep(10000);
        t.setLoop(false);
    }}class T extends Thread{
    private boolean loop = true;
    private int times = 0;
    
    @Override    public void run() {
        while (loop){
            System.out.println("hello" + (++times));
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void setLoop(boolean loop) {
        this.loop = loop;
    }}

四、线程常用方法

(一)第一组

1、setName:设置线程名称,使之与参数name相同。

2、getName:返回该线程名称。

3、start:使该线程开始执行,JAVA虚拟机底层调用该线程的start0方法。

4、run:调用线程对象的run方法。

5、setPriority:更改线程的优先级。

6、getPriority:获取线程的优先级。

7、sleep:在指定的毫秒数内,让当前正在执行的线程休眠。

8、interrupt:中断线程。

注意事项:

1、start()底层会创建新的线程,调用run(),run()就是一个简单的方法调用,不会启动新线程

2、中断线程一般用于中断正在休眠的线程,并没有真正的结束线程,所以如果线程中每输出内容后,会调用Thread.sleep()进行休眠的话,我们可以调用interrupt()方法将其提前唤醒

代码演示:

public class ThreadMethod01 {
    public static void main(String[] args) throws InterruptedException {
        T t = new T();
        t.setName("邱崇源");
        t.setPriority(1);
        t.start();
        for (int i = 0; i < 5; i++) {
            Thread.sleep(1000);
            System.out.println("hi" + i);
        }
        System.out.println(t.getName() + "优先级是" + t.getPriority());
        t.interrupt();
    }}class T extends Thread{
    @Override    public void run() {
        while (true){
            for (int i = 0; i < 100; i++) {
                System.out.println(Thread.currentThread().getName() + "正在吃包子" + i);
            }
            try {
                System.out.println(Thread.currentThread().getName() + "休眠中");
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                System.out.println(Thread.currentThread().getName() + "被唤醒了");
            }
        }
    }}

(二)第二组

1、yield:是一个静态方法,表示线程的礼让。让出CPU,让其他线程执行,但是不一定成功,因为这取决于CPU,如果CPU认为两个线程可以一起执行,则不进行礼让,所以如果CPU的核数多,并且线程数少,礼让就会大概率失败

2、join:表示线程的插队,假如主线程与子线程正在交替运行,我们想先让子线程执行完毕,然后再让主线程执行,就可以使用线程插队,在主线程中,创建子线程对象,并调用join方法,可以实现线程插队,线程插队一定会成功,先执行完插入线程任务后,再继续执行主线程

代码演示:

public class ThreadMethod02 {
    public static void main(String[] args) throws InterruptedException {
        A a = new A();
        a.start();
        for (int i = 1; i <= 20; i++) {
            System.out.println("主线程(小弟)吃了" + i + "个包子");
            Thread.sleep(1000);
            if (i == 5) {
                System.out.println("主线程(小弟)让子线程(大哥)先吃");
                a.join();
                //Thread.yield();
                System.out.println("子线程(大哥)吃完了,主线程(小弟)接着吃");
            }
        }
    }}class A extends Thread {
    @Override    public void run() {
        for (int i = 1; i <= 20; i++) {
            System.out.println("子线程(大哥)吃了" + i + "个包子");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }}

五、用户线程和守护线程

1、用户线程:也叫工作线程,线程的任务执行完或通知方式结束。

2、守护线程:一般是为工作线程服务的,当所有的用户线程结束守护线程自动结束

应用场景:

如果有两个线程,主线程运行结束,但子线程是无限循环。我们想让主线程结束的同时,子线程也结束,就需要让子线程变成守护线程。

在主线程中,创建子线程对象,并调用setDaemon(true),让子线程变成守护线程。

注意:一定要放在start方法之前

代码演示:

public class ThreadMethod03 {
    public static void main(String[] args) throws InterruptedException {
        MyDaemonThread myDaemonThread = new MyDaemonThread();
        myDaemonThread.setDaemon(true);
        myDaemonThread.start();
        for (int i = 1; i <= 10; i++) {
            System.out.println("宝强正在辛苦工作...");
            Thread.sleep(1000);
        }
        System.out.println("宝强回家了,宋喆仓惶跑路...");
    }}class MyDaemonThread extends Thread{
    @Override    public void run() {
        while (true){
            System.out.println("马蓉与宋喆正在爽歪歪...");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }}

六、线程的生命周期

1、JDK 中用 Thread.State 枚举表示了线程的几种状态

在这里插入图片描述

2、线程状态转换图

在这里插入图片描述

七、线程的同步

1、应用场景:

假如有100张票,有三个线程同时进入该方法买票,票就有可能超卖。所以我们需要线程同步机制,保证数据在同一时刻,最多有一个线程访问。

可以采取同步方法,在方法中加入synchronized关键字。

也可以采用同步代码块,synchronized(对象){}

注意:synchronized是非公平锁,如果这次第一个线程访问了数据,那么下一次第一个线程也有可能访问到数据。

如果同步方法是非静态的,那么锁可以是this,也可以是其他对象,但要求是同一个对象。

例:synchronized(this)

如果同步方法是静态的,锁为当前类本身。

例:synchronized(类名:class)

2、代码演示:

public class SellTicket {
    public static void main(String[] args) {
        SellTicket02 sellTicket04 = new SellTicket02();
        Thread thread1 = new Thread(sellTicket04);
        Thread thread2 = new Thread(sellTicket04);
        Thread thread3 = new Thread(sellTicket04);
        thread1.start();
        thread2.start();
        thread3.start();
    }}class SellTicket02 implements Runnable {
    public static int ticket = 100;
    private boolean loop = true;

    public synchronized void sell() {
        if (ticket <= 0) {
            loop = false;
            return;
        }
        System.out.println("卖出了一张票,还剩" + (--ticket) + "张");
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    @Override    public void run() {
        while (loop) {
            sell();
        }
    }}

八、线程的死锁

1、基本介绍

多个线程都占用了对方的锁资源,但不肯相让,就导致了死锁,在编程中,一定要避免死锁的发生。

2、发生场景:

例如:A和B的面前都各有两道门,A的第一道门是o1,第二道门是o2。B的第一道门是o2,第二道门是o1。他们的面前有两把锁,一个是o1锁,一个是o2锁,假如A抢到了o1锁,B抢到了o2锁,但是他们只可打开各自的第一道门,第二道门都没有打开,那么他们都无法释放自己的锁资源,又不可能相让,因此发生了死锁。

3、代码演示:

public class DeadLock_ {
	public static void main(String[] args) { //模拟死锁现象 
		DeadLockDemo A = new DeadLockDemo(true); 
		A.setName("A 线程"); 
		DeadLockDemo B = new DeadLockDemo(false); 
		B.setName("B 线程");
		A.start(); 
		B.start(); 
	} }class DeadLockDemo extends Thread { 
	static Object o1 = new Object();// 保证多线程,共享一个对象,这里使用 static 
	static Object o2 = new Object(); 
	boolean flag; 
	
	public DeadLockDemo(boolean flag) {//构造器 
		this.flag = flag; 
	}
	
	@Override 
	public void run() {  
		if (flag) { 
			synchronized (o1) { 
				System.out.println(Thread.currentThread().getName() + " 进入 1"); 
				synchronized (o2) { 
					System.out.println(Thread.currentThread().getName() + " 进入 2"); 
				} 
			} 
		} else {
			synchronized (o2) { 
				System.out.println(Thread.currentThread().getName() + " 进入 3"); 
				synchronized (o1) {  
					System.out.println(Thread.currentThread().getName() + " 进入 4"); 
				} 
			} 
		} 
	} }

九、释放锁

1、下面操作会释放锁

当前线程的同步方法,同步代码块执行结束。
当前线程在同步代码块,同步方法中遇到break,return
当前线程在同步代码块,同步方法中出现了未处理的错误或异常,导致异常结束。
当前线程在同步代码块,同步方法中执行的线程对象的wait方法,当前线程暂停,并释放锁。

2、 下面操作不会释放锁

线程执行同步代码块和同步方法时,程序调用Thread.sleep(),Thread.yield()方法暂停当前线程的执行,不会释放锁。
线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程挂起,该线程不会释放锁。

推荐学习:《java视频教程

以上是Java知识点总结之多线程基础的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文转载于:CSDN。如有侵权,请联系admin@php.cn删除
如何将Maven或Gradle用于高级Java项目管理,构建自动化和依赖性解决方案?如何将Maven或Gradle用于高级Java项目管理,构建自动化和依赖性解决方案?Mar 17, 2025 pm 05:46 PM

本文讨论了使用Maven和Gradle进行Java项目管理,构建自动化和依赖性解决方案,以比较其方法和优化策略。

如何使用适当的版本控制和依赖项管理创建和使用自定义Java库(JAR文件)?如何使用适当的版本控制和依赖项管理创建和使用自定义Java库(JAR文件)?Mar 17, 2025 pm 05:45 PM

本文使用Maven和Gradle之类的工具讨论了具有适当的版本控制和依赖关系管理的自定义Java库(JAR文件)的创建和使用。

如何使用咖啡因或Guava Cache等库在Java应用程序中实现多层缓存?如何使用咖啡因或Guava Cache等库在Java应用程序中实现多层缓存?Mar 17, 2025 pm 05:44 PM

本文讨论了使用咖啡因和Guava缓存在Java中实施多层缓存以提高应用程序性能。它涵盖设置,集成和绩效优势,以及配置和驱逐政策管理最佳PRA

如何将JPA(Java持久性API)用于具有高级功能(例如缓存和懒惰加载)的对象相关映射?如何将JPA(Java持久性API)用于具有高级功能(例如缓存和懒惰加载)的对象相关映射?Mar 17, 2025 pm 05:43 PM

本文讨论了使用JPA进行对象相关映射,并具有高级功能,例如缓存和懒惰加载。它涵盖了设置,实体映射和优化性能的最佳实践,同时突出潜在的陷阱。[159个字符]

Java的类负载机制如何起作用,包括不同的类载荷及其委托模型?Java的类负载机制如何起作用,包括不同的类载荷及其委托模型?Mar 17, 2025 pm 05:35 PM

Java的类上载涉及使用带有引导,扩展程序和应用程序类负载器的分层系统加载,链接和初始化类。父代授权模型确保首先加载核心类别,从而影响自定义类LOA

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
4 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
4 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
4 周前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
1 个月前By尊渡假赌尊渡假赌尊渡假赌

热工具

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

安全考试浏览器

安全考试浏览器

Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

螳螂BT

螳螂BT

Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具