java必学必会之线程(2)

Java必学必会之线程(2)攻略

线程同步

在多线程编程中,线程同步是一个非常重要的问题。如果不加以控制,在多线程同时访问共享资源的情况下,可能会导致数据不一致、死锁等问题。

同步的两种方式

Java 中实现同步的两种方式分别是 synchronized 和 ReentrantLock。

synchronized 关键字是 Java 提供的默认的语言级别的同步机制,可以用于实现方法或者块的同步。当一个线程调用 synchronized 方法时,其他线程可以调用对象的非 synchronized 方法,但是会阻塞,直到第一个线程执行完毕。

public synchronized void deposit(int amount) {  
    balance = balance + amount;  
}

ReentrantLock 则是 Java 提供的高级同步机制,可以更加灵活地对锁进行控制。与 synchronized 相比,ReentrantLock 支持更加灵活的同步方式,如公平锁、多个 Condition 等。

Lock lock = new ReentrantLock();  
...  
lock.lock();  
try {
    // 内部业务逻辑  
} finally {  
    lock.unlock();  
}

死锁的产生

在多线程编程中,死锁是常见的难题。死锁是指两个或多个线程在执行过程中,因竞争资源或互相等待而造成的一种互相等待的现象。

死锁原因通常有以下几种:

  • 竞争资源
  • 线程锁定顺序死锁
  • 动态的锁顺序死锁

以下示例说明了死锁的问题:

class DeliveryService{
    public synchronized void takeOrder(Order order){
        // 待实现的代码
    }
    public synchronized void deliverOrder(Order order){
        // 待实现的代码
    }
}

在上述示例代码中,当一个派送员在派送订单时,需要先占用 deliverOrder 方法的锁。而这个派送员在派送订单前,需要先接受顾客的订单,也就是占用 takeOrder 方法的锁。如果此时多个派送员同时接收订单,那么就会发生死锁。

避免死锁

避免死锁问题,一种方法是通过共享锁来实现同步。另外,还需要注意避免锁竞争、锁嵌套等问题。

以下是一些避免死锁的方法:

  • 破坏请求资源的环路
  • 使用尝试锁定机制
  • 按顺序加锁
  • 应用程序拥有锁的时长尽可能短

线程的池化

线程池是 Java 并发包提供的用于管理线程的工具。线程池由线程池管理器和一组工作线程组成。

如何使用线程池

int corePoolSize = 5;// 池中所保存的线程数,包括空闲线程。   
int maximumPoolSize = 10;// 池中允许的最大线程数。  
long keepAliveTime = 60000;// 当线程数大于核心线程数时,此为终止多余的空闲线程等待新任务的最长时间。     
BlockingQueue workQueue = new LinkedBlockingQueue();// 当线程池的任务队列满时,提交的任务将在此队列中等待。 
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime,TimeUnit.MILLISECONDS, workQueue);
threadPool.execute(new MyTask());// 调用execute方法添加一个要执行的任务
threadPool.shutdown();// 当添加任务后关闭线程池

线程池任务队列的选择

Java 中线程池任务队列的选择有以下几种:

  • LinkedBlockingQueue:基于链表的阻塞队列,按照先进先出的原则对任务进行排序。适用于任务比较频繁且任务处理时间比较短的情况。
  • ArrayBlockingQueue:基于数组的有界队列,适用于任务比较稳定的情况。
  • PriorityBlockingQueue:具有优先级的无界队列。

示例

同步示例

以下示例代码演示了使用 synchronize 关键字实现同步。

public class Counter {
    private int count = 0;
    public synchronized void increment() {
        count++;
    }
    public synchronized void decrement() {
        count--;
    }
    public synchronized int getCount() {
        return count;
    }
}

public class Worker extends Thread {
    private Counter counter;
    public Worker(Counter counter) {
        this.counter = counter;
    }
    public void run() {
        for (int i = 0; i < 1000000; i++) {
            counter.increment();
            counter.decrement();
        }
    }
}

public class Test {
    public static void main(String[] args) {
        Counter counter = new Counter();
        Worker[] workers = new Worker[10];
        for (int i = 0; i < 10; i++) {
            workers[i] = new Worker(counter);
            workers[i].start();
        }
        for (int i = 0; i < 10; i++) {
            try {
                workers[i].join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(counter.getCount());
    }
}

线程池示例

以下示例代码演示了使用线程池的方式执行任务。

public class TestThreadPool {
    public static void main(String[] args) {
        ExecutorService threadPool = Executors.newFixedThreadPool(5);
        for (int i = 0; i < 10; i++) {
            threadPool.execute(new Runnable() {
                public void run() {
                    System.out.println(Thread.currentThread().getName() + " is running");
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
        threadPool.shutdown();
    }
}

以上线程池中的任务将交给线程池中的工作线程执行,当全部任务执行完毕后,线程池会自动关闭。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:java必学必会之线程(2) - Python技术站

(0)
上一篇 2023年5月30日
下一篇 2023年5月30日

相关文章

  • Springboot启动流程详细分析

    Spring Boot 启动流程详细分析 Spring Boot 是一个基于 Spring 框架的快速应用开发框架,旨在尽可能简化 Spring 应用程序的创建、开发和部署。在 Spring Boot 的背后有一套强大的启动机制和自动化配置。 本文将深入探索 Spring Boot 的启动流程,包括 Spring Boot 的三种启动方式和启动核心类、主函数…

    Java 2023年5月15日
    00
  • Android使用MediaCodec将摄像头采集的视频编码为h264

    下面是 Android 使用 MediaCodec 将摄像头采集的视频编码为 h.264 的攻略。 1. 前置知识 在开始本教程前,需要掌握以下知识: Android 摄像头基础使用 h.264 视频编码基础知识 2. 初始化 MediaCodec 首先,我们需要初始化 MediaCodec。在编码 h.264 视频时,我们将使用 Android 自带的 M…

    Java 2023年5月20日
    00
  • SpringBoot集成多数据源解析

    关于“SpringBoot集成多数据源解析”的完整攻略,我会进行如下的讲解: 一、前置知识 在了解“SpringBoot集成多数据源解析”之前,需要你掌握以下的技术: SpringBoot SpringDataJPA 数据源的概念 二、什么是多数据源 “多数据源”是指在一个应用程序中使用多个数据库连接。 在一个应用程序中,不同的业务功能可能需要操作不同的数据…

    Java 2023年5月20日
    00
  • java实现dijkstra最短路径寻路算法

    下面是Java实现Dijkstra最短路径寻路算法的完整攻略: 什么是Dijkstra最短路径寻路算法 Dijkstra算法是一种可以求解带权重图(有向或无向)中的最短路径的算法。该算法要求图的权重为非负值。 Dijkstra算法实现思路 首先我们需要初始化:所有点的到起点的距离为无穷大,但起点到自己的距离为0。 然后从起点开始,将起点标记为已访问过,并将其…

    Java 2023年5月19日
    00
  • SpringBoot自动配置源码深入刨析讲解

    SpringBoot自动配置源码深入刨析讲解 SpringBoot自动配置是SpringBoot所提供的最为强大的功能之一。通过自动配置,我们可以很轻松地配置Spring应用程序,并且省去了很多配置的烦恼。 SpringBoot自动配置源码其实并不神秘,只要我们深入掌握其实现原理,就可以灵活地使用和定制自己的配置。 SpringBoot自动配置原理 Spri…

    Java 2023年5月15日
    00
  • Spring MVC拦截器_动力节点Java学院整理

    以下是关于“Spring MVC拦截器_动力节点Java学院整理”的完整攻略,其中包含两个示例。 Spring MVC拦截器 Spring MVC拦截器是一种用于拦截请求和响应的机制。在本文中,我们将讲解Spring MVC拦截器的实现原理及用法。 拦截器实现原理 Spring MVC拦截器的实现原理是通过实现HandlerInterceptor接口来实现的…

    Java 2023年5月17日
    00
  • SpringBoot高级配置之临时属性、配置文件、日志、多环境配置详解

    Spring Boot高级配置之临时属性、配置文件、日志、多环境配置详解 在Spring Boot应用程序中,我们需要进行高级配置,以满足不同的需求。本文将详细讲解Spring Boot高级配置,包括临时属性、配置文件、日志、多环境配置等。 临时属性 Spring Boot允许我们在运行时设置临时属性,这些属性将覆盖应用程序中的默认属性。以下是一个示例: @…

    Java 2023年5月15日
    00
  • Java日期时间及日期相互转换实现代码

    下面是“Java日期时间及日期相互转换实现代码”的完整攻略: 1. Java日期时间基础 Java 日期时间类是 Java API 内置的类,主要包括以下两个部分: 日期类:Date 类是 JDK 1.0 中的类,主要用于表示日期和时间。 日期格式类:DateFormat 是格式化日期时间的抽象类,它可以将 Date 类型的时间格式化为指定格式的字符串,也可…

    Java 2023年5月20日
    00
合作推广
合作推广
分享本页
返回顶部