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日

相关文章

  • Java线程池复用线程的秘密你知道吗

    Java线程池复用线程的秘密你知道吗 线程池的工作原理 线程池是专门用来管理线程的,其主要作用是维护一个空闲的线程队列和一个任务队列,将任务提交到线程池后,线程池会从线程队列中取出一个空闲线程,然后将任务分配给该线程执行,任务执行完毕后该线程就会返回线程队列等待执行下一个任务,这样就能大大提升线程的复用率和运行效率。 线程复用的实现 线程池中的线程是可以复用…

    Java 2023年5月19日
    00
  • JAVA项目常用异常处理汇总

    JAVA项目常用异常处理汇总 在JAVA项目开发过程中,异常是无法避免的,但是合理地处理异常可以提高项目的健壮性和稳定性。本文将介绍 JAVA 项目中常用的异常类型及处理方法。 JAVA 中常见异常类型 编译时异常 编译时异常是指在编译阶段就可以被检查出来的异常。比如: public class TestException { public static v…

    Java 2023年5月26日
    00
  • 浅谈JAVA字符串匹配算法indexOf函数的实现方法

    浅谈JAVA字符串匹配算法indexOf函数的实现方法 介绍 indexOf 是 JAVA 提供的一个用于字符串匹配的函数,它的作用是在一个给定的字符串中寻找另一个子字符串第一次出现的位置。在 JAVA 中,由于字符串是不可变的,所以 indexOf 是该语言中一个十分常用的方法。 indexOf的实现方法 在 JAVA 中,String 类有一个 inde…

    Java 2023年5月19日
    00
  • Spring扩展BeanFactoryPostProcessor使用技巧详解

    首先需要明确的是,BeanFactoryPostProcessor是在Spring容器实例化Bean之后,在Bean实例化之前处理BeanFactory中的BeanDefinition的接口。 一、BeanFactoryPostProcessor的使用场景 通常,在开发中,我们会利用BeanFactoryPostProcessor来修改或扩展BeanDefi…

    Java 2023年5月31日
    00
  • Java中动态规则的实现方式示例详解

    这篇文章将详细讲解Java中动态规则的实现方式,并且提供两个示例来帮助读者更好地理解此概念。在开始之前,我们来了解一下动态规则的概念。 什么是动态规则 动态规则是指在程序运行时可以动态地修改规则,而无需重新编译代码。这种实现方式增加了程序的灵活性和可维护性,而且不会影响程序的可靠性和性能。 Java中动态规则的实现方式有很多种,下面我们就来看两个示例。 示例…

    Java 2023年5月18日
    00
  • 出现java.lang.NoSuchMethodException异常的解决(靠谱)

    针对这个问题,以下是针对java.lang.NoSuchMethodException异常出现的完整攻略: 1. 异常原因分析 在程序运行过程中,如果出现java.lang.NoSuchMethodException异常,通常是因为程序调用了不存在的方法而导致的。具体分析原因可以按照以下步骤进行: 确认方法是否存在 确认方法的参数类型和顺序是否正确 确认调用…

    Java 2023年5月27日
    00
  • java中List、Array、Map、Set等集合相互转换

    下面为你讲解Java中List、Array、Map、Set等集合相互转换的完整攻略。 一、List与Array之间相互转换 1. 将List转换为数组 使用 List 的 toArray() 方法可以将 List 转换为数组。示例代码如下: List<String> list = new ArrayList<>(); list.add…

    Java 2023年5月27日
    00
  • 关于Java中你所不知道的Integer详解

    关于Java中你所不知道的Integer详解 前言 Integer是Java的基本数据类型之一,它在我们的日常编码中使用频率很高,但是它背后的一些特性可能并不为人所知,这篇文章将详细讲解。 Integer的使用 在Java中,我们通常会用Integer来表示整数数据类型。Integer的定义方式如下: Integer i = 10; 我们也可以通过下面的方式…

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