java 21 多线程

1.相关概念
进程:

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

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

线程:

线程是由进程创建的。是进程的一个实体;一个进程可以有多个线程;

Java 中线程被认为是一个CPU、程序代码、和数据的封装体。java.lang.Thread类使用户可以创建和控制自己的线程。在Java中,虚拟CPU是自动封装进Thread类的实例中,而Code和Data要通过一个对象传给Thread类的构造函数。

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

多线程:同一个时刻,可以执行多个线程

并发:

同一个时刻,多个任务交替执行 单核cpu实现的多任务就是并发 (造成一种"貌似同时"的错觉)

并行:

同一个时刻,多个任务同时执行。多核cpu可以实现并行

java从语言级别支持多线程 比如object中的wait(),notify()

线程体

线程的Code和Data构成线程体。线程体决定了线程的行为

通过run()方法来实现的 线程启动后系统就自动调用run()方法,通常,run方法执行了一个时间较长的操作

2.对线程的基本控制
a. 线程的启动: start()方法

该方法的调用把嵌入在线程中的虚拟CPU置为可运行(Runnable)状态。Runnable状态意味着该线程可以参加调度,被JVM运行,并不意味着线程会立即执行**。**

b.线程的结束:

设定一个标记变量,以结束相应的循环及方法

通知线程退出:

java 复制代码
package xiancheng;
public class ThreadExit {
    public static void main(String[] args) throws InterruptedException {
        Cat1 cat = new Cat1();
        cat.start();
        //如果希望main线程去控制t1 线程的终止,必须可以修改loop
        // 让t1 退出run方法,从而终止t1线程->通知方式
        //让主线程休眠10秒,再通知t1线程退出
        System.out.println("main线程休息10s");
        Thread.sleep(10*1000);

        cat.setLoop(false);
    }
}
class Cat1 extends Thread{
    int times = 0;
    private boolean loop = true;
    @Override
    public void run(){
        while (loop){
            System.out.println("11"+(++times)+Thread.currentThread().getName());
            //让该线程休眠一秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            if(times ==5){
                break;
            }
        }
    }

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

暂时阻止线程的执行:

复制代码
try {
    Thread.sleep(1000);
} catch (InterruptedException e) {
    throw new RuntimeException(e);
}

c.设定线程的优先级

d.线程分类
java 复制代码
package xiancheng;

import java.util.*;
public class TestThreadDaemon {
    public static void main(String args[]) {
        Thread t = new MyThread();
        t.setDaemon(true);
        t.start();
//主线程结束后 t也结束  将子线程设置成守护线程
        System.out.println( "Main--" + new Date());
        try{ Thread.sleep(500); }
        catch(InterruptedException ex){}
        System.out.println("Main End");
    }
}

class MyThread extends Thread {
    public void run() {
        for(int i=0; i<10; i++ ){
            System.out.println(  i + "--" + new Date());
            try{ Thread.sleep(100); }
            catch(InterruptedException ex){}
        }
    }
}//输出:
//Main--Wed Dec 04 19:01:01 CST 2024
//0--Wed Dec 04 19:01:01 CST 2024
//1--Wed Dec 04 19:01:01 CST 2024
//2--Wed Dec 04 19:01:01 CST 2024
//3--Wed Dec 04 19:01:02 CST 2024
//4--Wed Dec 04 19:01:02 CST 2024
//Main End
3.线程常用方法
a.第一组:

Thread类的静态方法currentThread**( )**返回当前线程。

当线程的状态未知时,用isAlive( )确定线程是否活着。返回true意味着线程已经启动,但还没有****运行结束。

**sleep方法:该方法用来使一个线程暂停运行一段固定的时间。在线程睡眠时间内,将运行别的线程。 **sleep( )结束后,线程将进入Runnable状态。

b.第二组
java 复制代码
package xiancheng;

public class Threadjoin {
    public static void main(String[] args) throws InterruptedException {
        T3 t3 = new T3();
        t3.start();

        for (int i = 0; i <=6; i++) {
            Thread.sleep(1000);
            System.out.println("main------------"+i);
            if(i==3){
                System.out.println("主线程执行3次了,就让子线程先执行(之前是同时执行的)");
                t3.join();
                System.out.println("子线程执行完了,主线程继续执行");
            }
        }
    }
}
class T3 extends Thread{
    @Override
    public void run(){
        for (int i = 0; i <6 ; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println("子线程------------------------"+i);
        }
    }
}

//子线程------------------------0
//main------------0
//main------------1
//子线程------------------------1
//子线程------------------------2
//main------------2
//子线程------------------------3
//main------------3
//主线程执行3次了,就让子线程先执行(之前是同时执行的)
//子线程------------------------4
//子线程------------------------5
//子线程执行完了,主线程继续执行
//main------------4
//main------------5
//main------------6
//
//Process finished with exit code 0
4.创建线程
a.继承Thread类
java 复制代码
package xiancheng;

public class Thread01 {
    public static void main(String[] args) throws InterruptedException {
        Cat cat = new Cat();
        cat.start();//启动线程  会启动Cat的run方法

        //main线程启动一个子线程 Thread-0,主线程不会阻塞,会继续执行
        //主线程和子线程交替执行
        System.out.println("主线程会继续执行"+Thread.currentThread().getName());
        for (int i = 0; i <10 ; i++) {
            System.out.println("主线程 i ="+i);
            Thread.sleep(1000);
        }
    }

}
//1.当一个类继承了Thread类,该类就可以当成线程使用
//2.重写run方法,写上自己的代码
//3. run() 是Thread类实现了Runnable接口的run方法
class Cat extends Thread{
    int times = 0;
    @Override
    public void run(){
        while (true){
            System.out.println("11"+(++times)+Thread.currentThread().getName());
            //让该线程休眠一秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            if(times ==5){
                break;
            }
        }
    }
}
b.Runnable接口

一个线程就是Thread类的一个实例**。**

java 复制代码
package xiancheng;

public class Thread02 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        //dog.start();//不能调用该方法
        //创建Thread对象,把Dog对象(实现Runable接口),放入Thread
        Thread thread = new Thread(dog);
        thread.start();

    }
}
class Dog implements Runnable{
    int count = 0;
    public void run(){
        while (true){
            System.out.println("hi" + (++count)+Thread.currentThread().getName());
            //休眠一秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }if(count ==10){
                break;
            }
        }
    }
}
c.多线程案列
java 复制代码
package xiancheng;

public class Thread03 {
    public static void main(String[] args) {
        T1 t1 = new T1();
        T2 t2 = new T2();
        Thread th1 = new Thread(t1);
        Thread th2 = new Thread(t2);
        th1.start();//启动第一个线程
        th2.start();//启动第二个线程
    }
}
class T1 implements Runnable{
    int count = 0;

    @Override
    public void run() {
        //每隔一秒输出he
       while (true){
           System.out.println("he"+"|"+(++count));
           try {
               Thread.sleep(1000);
           } catch (InterruptedException e) {
               throw new RuntimeException(e);
           }if(count ==10){
               break;
           }
       }

    }
}
class T2 implements Runnable{
    int count = 0;

    @Override
    public void run() {
        //每隔一秒输出he
       while (true){
           System.out.println("hello"+"|"+(++count));
           try {
               Thread.sleep(1000);
           } catch (InterruptedException e) {
               throw new RuntimeException(e);
           }if (count==10) {
               break;
           }
       }

    }
}
5.线程的生命周期
6.线程的同步

线程同步机制

在多线程编程,一些敏感数据不允许被多个线程同时访问,此时就使用同步访问技术,保证数据在任何同一时刻,最多有一个线程访问,以保证数据的完整性。

也可以这里理解:线程同步,即当有一个线程在对内存进行操作时,其他线程都不可以对这个内存地址进行操作,直到该线程完成操作,其他线程才能对该内存地址进行操作。

同步的具体方法------Synchronized

a.同步代码块

Synchronized(对象){得到对象的锁才能操作同步代码} 锁加在this对象上默认情况下

b.Synchronized放在方法声明中,相当于Synchronized(this),表示整个方法为同步方法

public Synchronized void m (String name){//需要被同步的代码}在同一时刻,只能有一个线程来执行该方锁加在this对象上

互斥锁

要求多个线程的锁对象为同一个!!

线程的死锁:

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

java 复制代码
package xiancheng;

class Worker
{
    int id;
    public Worker(int id){ this.id=id; }
    synchronized void doTaskWithCooperator(Worker other){
        try{ Thread.sleep(500); } catch(Exception e){}
        synchronized(other){
            System.out.println("doing" + id);
        }
    }
}

class DeadLockDemo{
    public static void main(String[] args) {
        Worker w1 = new Worker(1);
        Worker w2 = new Worker(2);
        Thread td1 = new Thread(()->{
            w1.doTaskWithCooperator(w2);
        });
        Thread td2 = new Thread(()->{
            w2.doTaskWithCooperator(w1);
        });
        td1.start();
        td2.start();
    }
}
//在方法内部,首先使用Thread.sleep(500)让当前线程休眠 500 毫秒,
// 然后又嵌套了一个synchronized块,它以传入的另一个Worker对象other作为锁对象。
// 在这个内部的synchronized块中,只是简单地输出了当前Worker对象的id值,表示正在执行相关任务。
//这里存在产生死锁的隐患,因为它获取了自身实例对应的锁(方法级别的synchronized隐式锁)后,
// 又尝试去获取另一个Worker实例对应的锁(通过synchronized(other)),
// 如果多个线程以交叉的方式去获取锁,就可能导致死锁情况发生。
释放锁:

1.当前线程的同步方法、同步代码块执行结束

2.同步方法中遇到break、return

3.当前线程在同步代码块,同步方法中出现了未处理的Error或Exception,导致异常结束

4.同步方法中执行了线程对象的wait()方法,当前线程暂停,并释当前线程在同步代码块、放锁。

线程执行同步代码块或同步方法时,程序调用Thread.sleep()、Thread.yield()方法暂停当前线程的执行,不会释放锁

线程执行同步代码块时,其他线程调用了该线程的suspend()方法将该线程挂起该线程不会释放锁。

相关推荐
m0_748241122 分钟前
【Spring】获取Cookie和Session(@CookieValue()和@SessionAttribute())
java·后端·spring
Eiceblue9 分钟前
在.NET用C#将Word文档转换为HTML格式
开发语言·vscode·c#·html·word·.net
步、步、为营10 分钟前
C#局部函数 VS Lambda表达式
开发语言·windows·c#
Kevinyu_12 分钟前
Java ArrayList
java·开发语言·windows
忆源13 分钟前
Linux高级--3.3.1 C++ spdlog 开源异步日志方案
java·c++·开源
stormjun27 分钟前
基于 Python 的深度学习的车俩特征分析系统,附源码
开发语言·python·深度学习·车辆特征分析·python 车辆特征分析
BinaryBardC28 分钟前
Dart语言的字符串处理
开发语言·后端·golang
数据的世界0132 分钟前
C#表达式和运算符
开发语言·c#
一只小菜鸡38 分钟前
python+django+Nacos实现配置动态更新-集中管理配置(实现mysql配置动态读取及动态更新)
开发语言·python·django
有梦想的咕噜40 分钟前
Qt Quick 和 Qt Designer
开发语言·qt