首页 > 编程语言 >Java多线程

Java多线程

时间:2024-10-30 20:47:47浏览次数:3  
标签:Java Thread void 线程 new 多线程 public

1.相关概念

1.1程序,进程与线程

程序(Program):为完成特定任务,用某种语言编写的一组指令的集合,即指一段静态的代码,静态对象。

进程 (Process)    进程是操作系统中执行的程序的实例。它是系统资源分配的基本单位,包括内存空间、文件描述符等。每个进程都有自己的地址空间,进程间的通信相对复杂,通常需要使用进程间通信 (IPC) 机制,如管道、消息队列等。

线程 (Thread)       :线程是进程中的一个执行单元,是程序执行的最小单位。一个进程可以包含多个线程,这些线程共享进程的资源,如内存和文件描述符。线程之间的通信相对简单,因为它们共享同一进程的地址空间。

1.2查看线程与进程

Java提供了Thread类来管理和查看线程。你可以使用以下方法获取当前线程的状态:

public class ThreadExample {
    public static void main(String[] args) {
        // 获取当前线程
        Thread currentThread = Thread.currentThread();
        
        // 打印线程名称
        System.out.println("Thread Name: " + currentThread.getName());
        
        // 打印线程优先级
        System.out.println("Thread Priority: " + currentThread.getPriority());
        
        // 打印线程状态
        System.out.println("Thread State: " + currentThread.getState());
    }
}

你可以使用Thread.getAllStackTraces()方法来获取所有线程的堆栈跟踪信息:

import java.util.Map;

public class AllThreadsExample {
    public static void main(String[] args) {
        // 获取所有线程的堆栈跟踪
        Map<Thread, StackTraceElement[]> allThreads = Thread.getAllStackTraces();
        
        // 遍历所有线程
        for (Map.Entry<Thread, StackTraceElement[]> entry : allThreads.entrySet()) {
            Thread thread = entry.getKey();
            StackTraceElement[] stackTrace = entry.getValue();
            
            // 打印线程名称和状态
            System.out.println("Thread Name: " + thread.getName() + ", State: " + thread.getState());
        }
    }
}

一个进程中包含多个线程 

 1.3线程调度

线程调度是操作系统或Java虚拟机(JVM)管理多个线程如何分配CPU时间的过程。以下是几个关键点:

  1. 线程优先级:Java允许为线程设置优先级(1到10),影响调度顺序,但不保证执行顺序。

  2. 时间片轮转:操作系统通常使用时间片轮转算法,给每个线程分配一定的CPU时间。

  3. 线程状态:线程有多种状态,包括新建、就绪、运行、阻塞和死亡,影响调度行为。

  4. 同步机制:使用synchronizedLock等工具确保对共享资源的安全访问,可能导致线程阻塞。

  5. Thread.sleep():使当前线程暂停一段时间,让其他线程执行,但不释放锁。

  6. Thread.yield():提示调度器当前线程愿意放弃CPU使用权,允许其他同级别或高优先级线程执行。

  7. 最佳实践:合理设计线程模型,避免过多依赖优先级和过度同步。

1.4多线程程序的优点

  • 并发执行:多线程可以同时执行多个任务,提高程序的整体性能和响应能力,特别是在多核处理器上。

  • 资源共享:线程之间可以共享内存和资源,减少资源消耗,相比于进程更轻量。

  • 响应性:在用户界面应用中,多线程可以在后台执行耗时任务,保持界面的响应性。

  • 提高吞吐量:对于需要长时间运行的任务(如网络请求或I/O操作),使用多线程可以提高系统的吞吐量。

  • 更好的利用系统资源:多线程可以更有效地利用CPU和其他系统资源,减少空闲时间。

  • 简化程序结构:在某些情况下,多线程可以使程序结构更清晰,例如将不同的功能模块分配给不同的线程。

  • 灵活性:多线程编程允许动态调整线程的数量,以适应不同的负载和需求。

  • 实现异步处理:通过使用线程,程序可以实现异步处理,提高效率,特别是在网络通信和文件处理等场景。

 1.5并行与并发

并行:指的是多个任务在同一时间点上真正同时执行。通常需要多核或多处理器系统。

并发:指的是多个任务在同一时间段内执行,但不一定是同时。任务可能会交替进行,系统在不同任务之间切换。

2.创建和启动线程 

2.1方式一:继承Thread类

package thread;

public class thread extends Thread{
    //1.创建一个继承于Thread的子类

    //2.重写Thread中的run()方法 ----->将此线程要执行的操作声明在此方法体中
    @Override
    public void run() {
        System.out.println("线程开始运行了!");
    }

    public static void main(String[] args) {
        //3.创建当前Thread的子类的对象
        thread t1=new thread();
        //4.通过对象调用start方法
        t1.start();
    }
}

2.2方式二实现Runnable接口 

package runnable;

public class Runnable implements java.lang.Runnable {
    //1.创建一个类实现Runnable接口
    //2.重写接口中的run()方法
    @Override
    public void run() {
        System.out.println("方法!");
    }

    public static void main(String[] args) {
//        //3.创建当前实现类的对象
//        Runnable r1=new Runnable();
//        //4.将此对象作为参数传递到Thread构造器中,创建Thread类的实例
//        Thread t1=new Thread(r1);
//        //5.通过Thread类的实例,调用start方法。
//        t1.start();
      /*  new Thread(new Runnable(){
            @Override
            public void run() {
                for (int i = 1; i <= 100; i++) {
                    if (i%2==0){
                        System.out.println(Thread.currentThread().getName()+i);
                    }
                }
            }
        }).start();*/
        new Thread(new java.lang.Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <= 100; i++) {
                    if (i%2!=0){
                        System.out.println(Thread.currentThread().getName()+i);
                    }
                }
            }
        }).start();

    }
}

3.线程的常用方法和生命周期

 3.1线程的常用结构

3.2线程中的常用方法

3.3线程的优先级 

 3.4线程的生命周期

 3.4.1JDK1.5之前:

3.4.2JDK1.5之后:

4.线程安全问题及解决

5.死锁

 5.1如何看待死锁?

不同的线程分别占用对方需要的资源不放弃,都在等对方放弃自己需要的同步资源,就形成了死锁。

我们编写程序时,避免出现死锁。

5.2诱发死锁的原因 

5.3如何避免死锁 

6.Lock锁

6.1步骤

class Window extends Thread {
    static int sticks = 100;
    //创建lock实例,需要确保多个线程共用一个lock实例需要考虑将此对象声明为static final
    private static final ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
           //执行lock方法,锁定对共享资源的共用
            try {
                lock.lock();
                if (sticks > 0) {
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    System.out.println(Thread.currentThread().getName() + "正在买票,还剩下" + sticks + "张票");
                    sticks--;

                }
                if (sticks == 0) {
                    return;
                }
            } finally {
                //unlock()释放对共享数据的锁定
                lock.unlock();
            }
        }
    }
}

public class exer1 {
    public static void main(String[] args) {
        Window t1 = new Window();
        t1.setName("窗口1");
        Window t2 = new Window();
        t2.setName("窗口2");
        Window t3 = new Window();
        t3.setName("窗口3");
        t1.start();
        t2.start();
        t3.start();
    }
}

6.2 synchronized同步的方式与lock的对比

 7.线程的通信 

7.1线程间通信的理解

当需要多个线程来完成一个共同的任务时,并且希望他们有规律的执行,那么多线程之间就需要一些通讯机制,可以协助他们的工作。即等待唤醒机制 。

7.2等待唤醒机制

class PrintNumber implements Runnable{
    private int i=1;
    @Override
    public void run() {
        while (true){
            synchronized (this) {
                notify();
                if (i<=100){
                    System.out.println(Thread.currentThread().getName()+":"+i);
                    i++;
                    try {
                        wait();//线程一旦进入该方法,就进入等待状态,同时,会释放对同步监视器的调用
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }else {
                    break;
                }
            }
        }
    }
}
public class exer2 {
    public static void main(String[] args) {
    PrintNumber p=new PrintNumber();
    Thread t1=new Thread(p);
    t1.setName("线程1");
    Thread t2=new Thread(p);
    t2.setName("线程2");
    t1.start();
    t2.start();
    }
}

 7.2.1注意点

7.2.2sleep和wait的区别

相同点:sleep和wait方法都可以使线程进入阻塞状态。

不同点:wait只能声明在同步代码块或同步方法中,而sleep任何位置都可声明。

              sleep不会释放对同步监视的调用,而wait会释放对同步监视器的调用。

              wait方法到达指定时间自动结束阻塞状态 或 通过被notify唤醒,结束阻塞。

              sleep方法到达指定时间自动结束阻塞。

 8.JDK5.0之后新增的两种多线程创建方式

8. 1多线程创建方式三:实现Callable结口

class NumThread implements Callable {
    //实现call()方法,将此线程需要执行的操作声明在call()中
    @Override
    public Object call() throws Exception {
        int sum = 0;
        for (int j = 1; j < 100; j++) {
            if (j % 2 == 0) {
                System.out.print(j + " ");
                sum += j;
            }
        }
        return sum;
    }
}

public class CallableTest {
    public static void main(String[] args) {
        //创建Callable接口实现类的对象
        NumThread numThread = new NumThread();
        //将此对象作为参数传递到FutureTask构造器中,创建FutureTask的对象
        FutureTask futureTask = new FutureTask<>(numThread);
        //将此对象作为参数传递到Thread构造器中,创建Thread的对象
        Thread t1 = new Thread(futureTask);
        t1.start();
        try {
            int num = (Integer) futureTask.get();
            System.out.println();
            System.out.println(num);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }
    }
}

 8.2多线程创建方式四:线程池

 问题:如果并发的线程数量很多,并且每一个线程执行任务的时间很短,这样频繁创建线程就会大大降低系统的效率,线程的创建和销毁都需要时间。

线程池的思路:如果提前创建好多个线程,放入线程池中,使用时直接获取,用完放回池中,可以避免频繁创建销毁线程,实现重复利用。

class Number implements Runnable{

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

    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            if ((i%2!=0)){
                System.out.println(Thread.currentThread().getName()+": "+i);
            }
        }
    }
}
public class ExecutorTest {
    public static void main(String[] args) {
       //1.提供指定线程数量的线程池
        ExecutorService executorService= Executors.newFixedThreadPool(10);
        ThreadPoolExecutor threadPoolExecutor=(ThreadPoolExecutor) executorService;
        //设置线程池的属性
        threadPoolExecutor.setMaximumPoolSize(50);//设置线程池中线程数的上限
        //2.执行指定的线程的操作,需要提供实现Runnable接口或Callable接口实现类的对象
        threadPoolExecutor.execute(new Number());//适合用于Runnable
        threadPoolExecutor.execute(new Number1());//适合用于Runnable
        //threadPoolExecutor.submit(Callable callable);//适合用于Callable
        //3.关闭线程池
        threadPoolExecutor.shutdown();
    }
}

标签:Java,Thread,void,线程,new,多线程,public
From: https://blog.csdn.net/2302_78998188/article/details/143306830

相关文章

  • java+vue计算机毕设大连疫情防控物资调配及管理系统【开题+程序+论文+源码】
    本系统(程序+源码)带文档lw万字以上文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景在新冠疫情全球肆虐的背景下,大连作为东北地区的重要港口城市和旅游胜地,面临着疫情防控的巨大挑战。疫情防控工作的有效实施,离不开充足、及时的物资保......
  • 【JavaEE初阶】深入理解TCP协议特性之延时应答,捎带应答,面向字节流以及异常处理
     前言......
  • 第4关:JAVA关键字测试题
    一、选择题 以下哪个是Java关键字?()A.functionB.classC.defD.var答案:B。“class”是Java中用于定义类的关键字。“function”是JavaScript等语言中的关键字;“def”是Python等语言中的关键字;“var”在Java10引入局部变量类型推断后有类似的作用,但不是......
  • 【java应用】jmeter玩法:BeanShell PreProcessor入口及常用方法介绍
    原创方知本知从零做软件测试现在的系统,信息安全性都在加强。因此,利用Jmeter进行接口压测的时候,通常需要实现模拟登录接口的加密功能。本系列文将介绍如何利用BeanShellPreProcessor实现AES、MD5以及RSA三种加密方法。1.1BeanShellPreProcessor入口在请求中添加前置处理......
  • 【java应用】 Jmeter玩法:调用jar包实现AES加密
    原创方知本知从零做软件测试一、将开发提供的AESjava类打成jar包1.1打开开发提供的java类用Eclipse开发工具打开,观察包名。新建项目,在生成的src目录下新建包,名字为java类对应的包名,将java类拖到该包下面。1.2将该java类导出成jar包格式二、Jmeter调用jar包实现AES加......
  • Java面试题中高级进阶(JVM篇01)
    前言本来想着给自己放松一下,刷刷博客,突然被几道面试题难倒!说说堆和栈的区别?什么时候会触发FullGC?什么是Java虚拟机?似乎有点模糊了,那就大概看一下面试题吧。好记性不如烂键盘***12万字的java面试题整理***说说堆和栈的区别栈是运行时单位,代表着逻辑,内含基本数据类型和......
  • java计算机毕业设计基于SpringBoot的疫苗接种管理系统(开题+程序+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着全球公共卫生事件的频发,疫苗接种成为预防和控制传染病的重要手段。传统的疫苗接种管理依赖于手工记录和纸质文件,这种方式不仅效率低下,而且容易出......
  • java计算机毕业设计基于springboot的个人博客设计与实现(开题+程序+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容基于SpringBoot的个人博客设计与实现的相关说明一、研究背景随着互联网的迅猛发展,个人博客作为一种便捷的网络表达和信息分享方式,受到了广泛的关注和应用。......
  • Java 集合框架是什么?集合框架的优点有哪些?
    目录1.Java集合框架的概念2.集合类3. Java在后续的版本中做了进一步的增强4.集合框架的优点1.Java集合框架的概念        Java集合框架(JavaCollectionsFramework,JCF)是Java中一个用于存储和处理对象集合的统一架构。它提供了一系列的接口和类,这些接口和......
  • Java集合框架中的泛型有什么优点?
    目录1.泛型的基本概念1.1什么是泛型1.2泛型与非泛型代码的比较2.使用泛型的优点2.1类型安全2.2 消除类型转换2.3使代码更整洁1.泛型的基本概念1.1什么是泛型        泛型是Java语言中一种支持类型参数化的技术,它允许在编译时提供类型信息,从而使得......