Java编程实践教程与实例详解

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:Java教程和实例提供了一个全面的资源集合,包含160多个实例程序来帮助学习者理解和掌握Java编程语言。教程涵盖了Java的基础语法、面向对象编程、异常处理、集合框架、IO流、多线程、网络编程、反射机制、枚举和注解、泛型、Lambda表达式、JDBC、GUI编程以及单元测试和项目管理工具Maven的应用。这些实例不仅涉及理论知识,也重视实践能力的提升,适用于希望提高Java编程技能的学习者。 java教程和实例

1. Java基础语法介绍与实践

Java作为一种广泛使用的编程语言,其基础语法是构建更复杂应用程序的基石。本章将带领读者了解Java的核心语法,并通过实际案例进行操作实践,从而加深对Java编程语言的理解。

1.1 Java程序的结构

Java程序由类(Class)组成,类中包含属性(Fields)和方法(Methods)。每个Java程序必须包含一个公共类,并且该类的名称必须与文件名相匹配。一个简单的Java程序结构如下:

public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
    }
}

在这段代码中, public class HelloWorld 定义了一个公共类 HelloWorld ,其中 main 方法是程序的入口点。 System.out.println 是一个输出语句,用于在控制台上打印字符串。

1.2 Java变量与数据类型

Java是一种强类型语言,这意味着每个变量和表达式都有一个确定的类型,而类型检查发生在编译时期。Java的基本数据类型包括整型(如int)、浮点型(如double)、字符型(如char)和布尔型(如boolean)。

int number = 10;
double price = 20.50;
char grade = 'A';
boolean isTrue = true;

在声明变量时,必须指定数据类型,并且每个变量只能声明一次类型。基本数据类型存储的是数据本身的值,而引用类型(如类、接口、数组)存储的是对象的引用。

1.3 控制语句与代码块

控制流语句允许我们改变代码的执行顺序。Java提供了多种控制语句,如条件语句(if-else、switch-case)和循环语句(for、while、do-while)。代码块是由一对大括号 {} 包围的代码集合,定义了一个作用域,变量在这个作用域内声明,仅在此代码块内可见。

if (number > 0) {
    System.out.println("Positive Number");
} else {
    System.out.println("Non-positive Number");
}

for (int i = 0; i < 10; i++) {
    System.out.println("Counting: " + i);
}

以上代码演示了使用条件语句和循环语句的基本用法。对于控制流的更复杂应用,我们将在后续章节中进行详细探讨。

通过本章的介绍,我们已经对Java的基础语法有了一个初步的了解。随着后续章节内容的深入,我们将不断实践这些基础知识,并逐步构建起强大的Java编程能力。

2. 面向对象编程概念与技巧

2.1 类与对象

2.1.1 类的定义和对象的创建

在Java中,类(Class)是创建对象的模板或蓝图。类定义了一组属性和方法,这些属性和方法共同描述了类的对象的特征和行为。对象则是类的实例,每个对象都有自己的状态和行为。

类的定义:

public class Car {
    // 属性(成员变量)
    private String make;
    private String model;
    private int year;

    // 方法
    public void start() {
        System.out.println("The car is starting.");
    }
    // 构造方法
    public Car(String make, String model, int year) {
        this.make = make;
        this.model = model;
        this.year = year;
    }
    // Getter和Setter方法
    public String getMake() {
        return make;
    }

    public void setMake(String make) {
        this.make = make;
    }

    public String getModel() {
        return model;
    }

    public void setModel(String model) {
        this.model = model;
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }
}

对象的创建和使用:

public class Main {
    public static void main(String[] args) {
        // 创建Car类的一个对象
        Car myCar = new Car("Toyota", "Corolla", 2020);
        // 调用对象的方法
        myCar.start();
        // 访问对象的属性
        System.out.println("Make: " + myCar.getMake());
        System.out.println("Model: " + myCar.getModel());
        System.out.println("Year: " + myCar.getYear());
    }
}

在这个例子中,我们定义了一个 Car 类,包含 make model year 三个属性,以及 start() 一个方法。此外,我们还提供了一个构造方法来初始化对象,以及对应的getter和setter方法来访问和修改对象的属性。在 Main 类的 main 方法中,我们创建了 Car 类的一个实例,并调用了它的方法和访问了它的属性。

2.1.2 类与对象的关系和区别

关系: - 类是对象的模板,对象是类的实例。 - 类是抽象的,对象是具体的。 - 一个类可以创建多个对象,它们都拥有类的属性和方法,但每个对象都有自己的属性值。

区别: - 类描述了一类事物的共同属性和行为,是抽象的;对象是类的具体实例,是实际存在的。 - 类的定义不会分配内存空间,对象的创建会分配内存空间。 - 类是静态的定义,对象是动态的实例。

2.2 封装、继承和多态

2.2.1 封装的基本概念和实现方式

封装是面向对象编程的一个重要原则,它指的是将对象的状态(属性)隐藏起来,通过定义公共的方法来访问和修改这些状态。这样做可以保护对象内部状态不被外部随意访问和修改,从而保证了对象内部数据的完整性和安全性。

实现封装的方法: - 使用私有(private)访问修饰符来修饰类的属性。 - 提供公共(public)的getter和setter方法,用于访问和修改私有属性。

public class Person {
    private String name; // 私有属性

    public Person(String name) {
        this.name = name;
    }

    // Getter方法
    public String getName() {
        return name;
    }

    // Setter方法
    public void setName(String name) {
        this.name = name;
    }
}

在这个例子中, Person 类有一个私有属性 name 。外部代码不能直接访问 name 属性,而必须通过 getName() setName() 方法来获取和设置它的值。这样就实现了对 name 属性的封装。

2.2.2 继承的机制和多态的表现

继承是面向对象编程的另一个核心概念。它允许创建一个新类,这个新类继承了另一个类的属性和方法,同时还可以扩展自己的功能。继承机制提高了代码的可重用性,也便于对代码的维护和管理。

继承的机制: - 通过使用 extends 关键字,可以创建一个类的子类。 - 子类继承父类的属性和方法,同时可以添加自己的属性和方法。

public class Employee extends Person {
    private String department;

    public Employee(String name, String department) {
        super(name); // 调用父类的构造方法
        this.department = department;
    }

    // Getter和Setter方法
    public String getDepartment() {
        return department;
    }

    public void setDepartment(String department) {
        this.department = department;
    }
}

在这个例子中, Employee 类继承了 Person 类。它有自己的属性 department ,并可以调用 Person 类的构造方法和方法。

多态的表现: - 多态允许我们使用一个父类的引用来指向一个子类的对象。 - 根据对象的实际类型,调用相应的方法。

public class Main {
    public static void main(String[] args) {
        Person person = new Person("Alice");
        Employee employee = new Employee("Bob", "IT");

        // Person类引用指向Employee类对象
        person = employee;
        // 多态:调用的是Employee类的getName()方法
        System.out.println(person.getName()); // 输出 "Bob"
    }
}

在这个例子中, Main 类的 main 方法中创建了 Person Employee 类的对象,并将 Employee 对象赋值给 Person 类型的引用。当我们调用 getName() 方法时,实际上调用的是 Employee 类中重写的 getName() 方法,这就是多态的体现。

2.2.3 继承与组合的对比分析

继承和组合是面向对象编程中两种重要的代码复用方式。它们各自有适用的场景和优缺点,合理选择可以提高代码的设计质量。

继承的特点: - 继承表示“是一个”(is-a)关系。 - 子类是父类的一种特殊形式,它具备父类的所有属性和行为。 - 继承可以创建出专门的子类。

组合的特点: - 组合表示“有一个”(has-a)关系。 - 类通过使用其他类的对象作为其成员变量来实现复杂的功能。 - 组合提供了更高的灵活性和更低的耦合度。

public class Engine {
    public void start() {
        System.out.println("Engine is starting...");
    }
}

public class Car {
    private Engine engine;

    public Car() {
        engine = new Engine();
    }

    public void startCar() {
        engine.start(); // 组合使用Engine类的方法
        System.out.println("Car is starting...");
    }
}

在这个例子中, Car 类通过组合使用了 Engine 类的对象。 Car 对象通过 Engine 对象的方法启动发动机,这种方式就是组合。相比之下,如果我们使用继承,那么 Car 类将会扩展 Engine 类,变成 Car Engine 的一种特殊形式。

继承和组合各有优缺点,继承容易实现且可以保持方法的一致性,但会增加类之间的耦合度;而组合提供了更高的灵活性,可以降低类之间的耦合度,但实现起来相对复杂。在实际开发中,应当根据具体需求和设计原则来选择合适的实现方式。

3. Java异常处理机制详解

3.1 异常类的层次结构

Java 异常处理机制是 Java 语言中非常重要的特性之一,它使得程序能够处理运行时的错误和异常情况。了解异常类的层次结构是掌握异常处理机制的基础。

3.1.1 Java异常体系概览

Java 中所有的异常都是 Throwable 类的实例,而 Throwable 类是 Error 和 Exception 的父类。Error 用来表示严重的错误,这些错误通常是不可恢复的,例如虚拟机错误(OutOfMemoryError)等。Exception 则是程序可以处理的异常,我们通常说的异常处理主要指的是 Exception 类型的异常。

在 Exception 类下,可以细分为两类异常:checked exception 和 unchecked exception。checked exception 是编译器需要检查的异常,如 IOException。unchecked exception 包括运行时异常(runtime exception)和错误(error),它们不被编译器强制检查,如 ArithmeticException。

3.1.2 常见的异常类介绍
  • IOException:表示在输入输出过程中遇到的异常情况,如打开不存在的文件、读写错误等。
  • SQLException:在进行数据库操作时可能会抛出的异常,如 SQL 语法错误、连接失败等。
  • NullPointerException:当尝试访问 null 对象的成员变量或方法时会抛出此异常。
  • ArithmeticException:算术运算时,如整数除以零,会抛出这个异常。

3.2 异常的捕获和处理

3.2.1 try-catch-finally语句的使用

在 Java 中,异常的捕获和处理主要通过 try-catch-finally 语句来实现。try 块中包含可能产生异常的代码,catch 块用来捕获并处理特定类型的异常,finally 块中的代码无论是否发生异常都会执行。

try {
    // 可能产生异常的代码
} catch (IOException e) {
    // 处理IOException类型的异常
} catch (Exception e) {
    // 处理其他类型的异常
} finally {
    // 无论是否发生异常都会执行的代码
}

逻辑分析: - 代码首先尝试执行 try 块中的语句。 - 如果 try 块中的任何语句抛出了 catch 中指定的异常类型,则执行相应的 catch 块。 - 如果 try 块中抛出了一个异常,但是没有 catch 块来捕获它,则异常会被传递到方法的调用者。 - finally 块无论 try 块中的代码是否抛出异常都会执行。它是用来执行一些清理工作,比如关闭文件流或数据库连接。

3.2.2 自定义异常类和抛出异常

Java 允许我们通过继承 Exception 或其子类来创建自定义异常类。这通常用于设计复杂的业务逻辑,需要明确区分不同类型的异常。

public class MyCustomException extends Exception {
    public MyCustomException(String message) {
        super(message);
    }
}

逻辑分析: - MyCustomException 类继承了 Exception 类,它通过构造函数接收一个字符串作为异常信息。 - 在业务逻辑中,你可以通过 throw 关键字来抛出这个异常。

public void myBusinessMethod() throws MyCustomException {
    if (/* some condition */) {
        throw new MyCustomException("业务逻辑异常");
    }
}

逻辑分析: - myBusinessMethod 方法使用了 throws 关键字声明了它可能抛出的异常类型 MyCustomException。 - 在方法体内,如果某些条件满足(此处为示例条件),就抛出 MyCustomException 异常。

通过自定义异常和标准异常的结合使用,开发者可以更精确地控制程序的异常流,让程序的错误处理更加清晰和专业。

4. Java集合框架的使用方法

4.1 集合框架概述

4.1.1 集合框架的基本结构

Java集合框架(Java Collections Framework)是一系列接口、实现类和算法的集合,它提供了一套标准的方法来操作和处理集合数据。集合框架的目的是为了更好地存储和操作对象群组。

集合框架的基本结构由以下几个部分组成:

  • 接口:为集合对象定义操作规范。
  • 实现类:根据接口规范实现具体功能。
  • 算法:对集合进行排序、搜索和其他操作。

其中,核心接口包括 Collection (单个元素集合)、 Map (键值对集合)等。而主要的实现类,例如 ArrayList LinkedList HashSet HashMap 等,提供了具体的数据结构来存储和管理集合对象。

4.1.2 集合框架中接口与实现类的关联

集合框架中的接口与实现类之间存在清晰的层次关系和继承关系。接口定义了方法的签名,而实现类则提供了这些方法的具体实现。例如:

  • List 接口定义了有序集合的操作, ArrayList LinkedList 都实现了此接口。
  • Set 接口定义了不包含重复元素的集合, HashSet LinkedHashSet 提供了不同的实现方式。
  • Map 接口则定义了键值对集合的操作, HashMap TreeMap 是其常见的实现。

通过了解这些接口和实现类的关系,开发者可以更有效地选择和使用适合特定需求的集合实现。

4.2 List、Set与Map的使用

4.2.1 List集合的操作方法

List 是一个有序的 Collection 接口,它允许重复的元素。 List 的主要实现类有 ArrayList LinkedList

以下是一个使用 ArrayList 的示例代码:

import java.util.ArrayList;
import java.util.List;

public class ListExample {
    public static void main(String[] args) {
        // 创建ArrayList实例并添加元素
        List<String> list = new ArrayList<>();
        list.add("Java");
        list.add("is");
        list.add("Awesome");

        // 输出ArrayList内容
        System.out.println(list);

        // 获取和修改元素
        System.out.println(list.get(1)); // 输出: is
        list.set(1, "very");
        System.out.println(list);

        // 删除元素
        list.remove(0);
        System.out.println(list);
    }
}

ArrayList 提供了灵活的动态数组实现,适合频繁随机访问元素。而 LinkedList 提供了双端队列和列表的实现,适合频繁的元素插入和删除操作。

4.2.2 Set集合的特性及应用

Set 是一个不允许重复元素的 Collection 接口,适合用于表示数学中的集合概念。

主要实现类 HashSet 通过哈希表实现,提供了快速的查找速度。 LinkedHashSet 则保持了元素插入的顺序。以下是使用 HashSet 的示例:

import java.util.HashSet;
import java.util.Set;

public class SetExample {
    public static void main(String[] args) {
        // 创建HashSet实例并添加元素
        Set<String> set = new HashSet<>();
        set.add("Java");
        set.add("is");
        set.add("Awesome");

        // 输出HashSet内容
        System.out.println(set);
    }
}

HashSet 在添加元素时,会调用元素的 hashCode() 方法和 equals() 方法来确保集合中不包含重复元素。

4.2.3 Map集合的键值对管理

Map 接口提供了一种映射机制,它存储键值对并允许快速查找和更新。 HashMap TreeMap Map 接口的两个常用实现类。

以下是一个使用 HashMap 的示例:

import java.util.HashMap;
import java.util.Map;

public class MapExample {
    public static void main(String[] args) {
        // 创建HashMap实例并添加键值对
        Map<String, String> map = new HashMap<>();
        map.put("Java", "Programming Language");
        map.put("Python", "Programming Language");
        map.put("Java", "Most Popular");

        // 输出HashMap内容
        System.out.println(map);

        // 获取和修改键值对
        System.out.println(map.get("Java")); // 输出: Most Popular
        map.put("Python", "Very Easy");
        System.out.println(map);

        // 删除键值对
        map.remove("Python");
        System.out.println(map);
    }
}

HashMap 不保证映射的顺序,它使用哈希表来存储键值对,提供快速的查找速度。而 TreeMap 则使用红黑树结构,键值对会被排序,并支持一系列的排序方法。

总结来看,Java集合框架为开发者提供了丰富的数据结构和操作方法,以便于更加高效地管理数据集合。通过理解和掌握其接口和实现类的使用,开发者可以针对不同的应用场景选择最合适的集合类型。

5. Java IO流操作技术

5.1 IO流的基本概念

5.1.1 IO流的分类和功能

在Java中,IO流是用于处理数据传输的机制,它使得程序可以读取和写入数据。Java的IO流系统非常强大,被广泛应用于文件操作、网络通信等领域。IO流主要分为两大类:输入流(Input Streams)和输出流(Output Streams)。

输入流主要用于从源读取数据到程序中,而输出流则将程序中的数据写入到目标。源可以是文件、网络连接,甚至是内存中的数据结构。目标同样可以是文件、网络连接等。

输入流和输出流根据数据的类型,可以进一步分为字节流和字符流。

  • 字节流 :字节流处理的是原始的字节数据,是最底层的数据处理方式。在处理文本文件时,字节流不会考虑字符编码问题,直接以字节为单位进行读写。
  • 字符流 :字符流则主要用于处理字符数据,它会根据指定的字符编码处理数据,更适合处理文本文件。Java中的 Reader Writer 是字符流的两个抽象基类。

除了基本的分类,Java IO流还提供了一系列的装饰器模式实现(Decorator Pattern),允许在现有流的基础上增加额外的功能,如缓冲(Buffering)、过滤(Filtering)、转换(Converting)等。

5.1.2 字节流与字符流的区别

在Java中,字节流与字符流虽然功能相似,但在处理文本数据时,两者有明显的区别:

  • 字节流 :由于字节流是基于字节的,所以它可以不受字符编码的限制处理任何二进制数据。例如,音频文件、视频文件等都可以用字节流来处理。

  • 字符流 :字符流则主要针对文本数据,能够处理文本文件中的编码转换。当使用字符流读取文本数据时,流会自动将字节转换为特定编码的字符。相反,在写入文件时,字符流也会将字符转换为字节。

字节流和字符流的选择主要取决于应用场景。对于二进制文件,如图片、音频和视频等,通常使用字节流。对于文本文件,尤其是涉及到字符编码的文本文件,使用字符流可以避免编码错误,提高代码的可移植性。

在Java的IO库中,字节流的基类是 InputStream OutputStream ,而字符流的基类是 Reader Writer 。这些基类定义了一系列标准的方法,如 read() write() ,用于数据的读取和写入。

5.2 文件读写操作实践

5.2.1 文件输入输出流的使用

在Java中进行文件读写操作,可以使用 FileInputStream FileOutputStream 来处理字节数据,使用 FileReader FileWriter 处理字符数据。以下是如何使用这些流进行基本的文件读写操作:

import java.io.*;

public class FileReadWriteExample {
    public static void main(String[] args) {
        String sourceFile = "source.txt";
        String targetFile = "target.txt";
        // 文件复制示例 - 字节流
        try (FileInputStream fis = new FileInputStream(sourceFile);
             FileOutputStream fos = new FileOutputStream(targetFile)) {
            int b;
            while ((b = fis.read()) != -1) {
                fos.write(b);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 文件复制示例 - 字符流
        try (FileReader fr = new FileReader(sourceFile);
             FileWriter fw = new FileWriter(targetFile)) {
            int c;
            while ((c = fr.read()) != -1) {
                fw.write(c);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

在使用文件流时,通常要确保资源被正确关闭,避免资源泄漏。在上面的例子中,使用了try-with-resources语句,它保证了在try语句块执行完毕后,无论是否发生异常,都会自动关闭流。

5.2.2 文件的复制、追加和转换操作

文件复制操作

前面的例子已经演示了如何使用Java IO流进行简单的文件复制。这里将介绍更高级的复制操作,例如带缓冲的复制。

import java.io.*;

public class AdvancedFileCopy {
    public static void copyFileWithBuffer(String source, String destination) throws IOException {
        try (FileInputStream fis = new FileInputStream(source);
             BufferedInputStream bis = new BufferedInputStream(fis);
             FileOutputStream fos = new FileOutputStream(destination);
             BufferedOutputStream bos = new BufferedOutputStream(fos)) {
            byte[] buffer = new byte[1024];
            int length;
            while ((length = bis.read(buffer)) > 0) {
                bos.write(buffer, 0, length);
            }
        }
    }
}

在这个例子中,使用了缓冲流 BufferedInputStream BufferedOutputStream 。缓冲流可以减少对底层系统的调用次数,提高文件操作的效率,尤其是在处理大文件时。

文件追加操作

在进行日志记录或其他场景时,我们可能需要向文件末尾追加内容。这可以通过指定构造函数的第二个参数为 true 来实现,如下例所示:

import java.io.*;

public class FileAppendExample {
    public static void appendToFile(String filePath, String text) throws IOException {
        try (FileWriter writer = new FileWriter(filePath, true)) {
            writer.write(text);
        }
    }
}
文件转换操作

文件转换操作指的是将文件从一种编码转换为另一种编码。以下是如何使用字符流来完成这个任务的示例:

import java.io.*;

public class FileConvertExample {
    public static void convertFileEncoding(String sourcePath, String targetPath, String fromEncoding, String toEncoding) throws IOException {
        try (FileReader reader = new FileReader(sourcePath, Charset.forName(fromEncoding));
             FileWriter writer = new FileWriter(targetPath, Charset.forName(toEncoding))) {
            int c;
            while ((c = reader.read()) != -1) {
                writer.write(c);
            }
        }
    }
}

在上面的例子中, Charset.forName() 方法用于指定字符流使用的具体编码类型。这样可以确保在读取和写入文件时字符编码能够正确转换。

通过本章节的介绍,我们了解了Java IO流的基本概念、分类和功能。接着,通过文件操作的实践,我们学会了如何使用文件输入输出流进行基本的读写操作,以及如何进行文件的复制、追加和转换等高级操作。掌握了这些基础和技能,可以帮助我们在开发中更高效地处理数据输入输出任务。

6. Java多线程编程技巧

Java作为一门面向对象的编程语言,其多线程编程能力是提升应用性能和实现复杂任务并行处理的关键。理解并掌握Java多线程编程的技巧对于每一位Java开发者而言都至关重要。

6.1 线程的创建与运行

6.1.1 实现Runnable接口和继承Thread类

在Java中,创建线程有两种基本方式:通过实现Runnable接口或继承Thread类。每种方式都有其特定的使用场景和优缺点。

实现Runnable接口

这种方式更符合面向对象的设计原则,因为它允许我们在不破坏封装性的前提下,实现多线程。

class MyRunnable implements Runnable {
    @Override
    public void run() {
        // 执行线程代码
        System.out.println("This is a thread created by implementing Runnable interface.");
    }
}

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

通过上面的代码,我们创建了一个实现了Runnable接口的MyRunnable类,并在main方法中实例化了Thread对象,传入了MyRunnable的实例。这样做的好处是可以通过实现同一个Runnable接口实现多个Thread实例。

继承Thread类

直接继承Thread类是另一种创建线程的方法,它更简单直观,但不适合多继承的场景。

class MyThread extends Thread {
    @Override
    public void run() {
        // 执行线程代码
        System.out.println("This is a thread created by extending Thread class.");
    }
}

public class Main {
    public static void main(String[] args) {
        MyThread myThread = new MyThread();
        myThread.start();
    }
}

通过继承Thread类,我们创建了MyThread子类,并覆盖了run()方法,然后在main方法中创建了MyThread对象,并调用start()方法启动线程。

6.1.2 线程的状态管理和优先级设置

Java线程有六种状态,分别是NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING和TERMINATED。了解这些状态对于管理线程生命周期和调试多线程程序至关重要。

线程优先级可以设置,范围是1(最低)到10(最高)。默认情况下,每个线程都会被分配一个优先级NORM_PRIORITY。

Thread thread = new Thread(new MyRunnable());
thread.setPriority(Thread.MAX_PRIORITY); // 设置线程优先级为最高
thread.start();

6.2 线程同步与通信

6.2.1 同步方法和同步块的使用

在多线程环境中,访问共享资源时常常需要进行同步处理,以避免数据不一致的问题。Java提供了synchronized关键字来实现线程同步。

同步方法

同步方法会锁定整个对象实例,在同一时刻只能由一个线程访问。

class SharedObject {
    synchronized public void accessResource() {
        // 操作共享资源
    }
}

同步块

同步块允许你指定被锁定对象,这样可以提高效率。

class SharedObject {
    Object lock = new Object();

    public void accessResource() {
        synchronized (lock) {
            // 操作共享资源
        }
    }
}

6.2.2 线程之间的协作与通信机制

线程之间可以通过wait()、notify()和notifyAll()方法进行协作,这些方法必须在同步块中调用。

synchronized (lock) {
    while (条件不满足) {
        lock.wait(); // 等待
    }
    // 条件满足后,其他线程调用notify()唤醒
    lock.notify();
}

6.3 线程池的使用与管理

6.3.1 线程池的基本概念和优势

线程池是一种多线程处理形式,它能够有效地管理线程并减少创建和销毁线程的开销。线程池适用于需要大量线程执行任务的场景,可以有效利用资源并降低系统开销。

6.3.2 线程池的配置和工作原理

Java提供了Executors工具类来简化线程池的创建和管理。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolExample {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(4); // 创建固定大小为4的线程池

        for (int i = 0; i < 10; i++) {
            executor.submit(new Task()); // 提交任务
        }

        executor.shutdown(); // 关闭线程池
    }
}

class Task implements Runnable {
    @Override
    public void run() {
        System.out.println("Task executed by thread pool");
    }
}

在上面的示例中,我们创建了一个固定大小为4的线程池,并提交了10个任务。每个任务将在某个线程池中的线程执行。

线程池的工作原理是通过管理一组工作线程来执行任务。它根据需要自动创建和回收线程,重用现有的线程来执行提交的任务,从而减少线程创建和销毁的开销,提升性能。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:Java教程和实例提供了一个全面的资源集合,包含160多个实例程序来帮助学习者理解和掌握Java编程语言。教程涵盖了Java的基础语法、面向对象编程、异常处理、集合框架、IO流、多线程、网络编程、反射机制、枚举和注解、泛型、Lambda表达式、JDBC、GUI编程以及单元测试和项目管理工具Maven的应用。这些实例不仅涉及理论知识,也重视实践能力的提升,适用于希望提高Java编程技能的学习者。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

AI实战-学生生活方式模式数据集分析预测实例(含24个源代码+69.54 KB完整的数据集) 代码手工整理,无语法错误,可运行。 包括:24个代码,共149.89 KB;数据大小:1个文件共69.54 KB。 使用到的模块: pandas os matplotlib.pyplot seaborn plotly.express warnings sklearn.model_selection.StratifiedShuffleSplit sklearn.pipeline.Pipeline sklearn.compose.ColumnTransformer sklearn.impute.SimpleImputer sklearn.preprocessing.OrdinalEncoder numpy sklearn.model_selection.cross_val_score sklearn.linear_model.LinearRegression sklearn.metrics.mean_squared_error sklearn.tree.DecisionTreeRegressor sklearn.ensemble.RandomForestRegressor sklearn.model_selection.train_test_split sklearn.preprocessing.PowerTransformer imblearn.pipeline.Pipeline imblearn.over_sampling.SMOTE sklearn.ensemble.AdaBoostClassifier sklearn.metrics.accuracy_score sklearn.metrics.precision_score sklearn.metrics.recall_score sklearn.metrics.f1_score optuna scipy.stats torch torch.nn torchvision.transforms torchvision.models torch.optim cv2 glob glob.glob torch.utils.data.DataLoader torch.utils.data.Dataset random.shuffle torch.utils.data.random_split torchsummary.summary matplotlib.ticker pyspark.sql.SparkSession pyspark.sql.functions.count pyspark.sql.functions.max pyspark.sql.functions.min pyspark.sql.functions.avg pyspark.sql.functions.stddev_samp pyspark.sql.functions.skewness pyspark.sql.functions.kurtosis pyspark.sql.functions pyspark.ml.feature.Tokenizer pyspark.ml.feature.VectorAssembler sklearn.preprocessing.LabelEncoder keras.models.Sequential keras.layers.Dense keras.utils.to_categorical ptitprince statsmodels.distributions.empirical_distribution.ECDF statsmodels.stats.outliers_influence.variance_inflation_factor ppscore sklearn.feature_selection.mutual_info_classif sklearn.decomposition.PCA sklearn.model_selection.StratifiedKFold sklearn.tree.DecisionTreeClassifier sklearn.metrics.balanced_accuracy_score sklearn.metrics.confusion_matrix mlxtend.plotting.plot_confusion_matrix scipy.stats.pearsonr scipy.stats.f_oneway sklearn.feature_selection.mutual_info_regression sklearn.feature_selecti
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值