Java创建多线程异步执行实现代码解析

Java创建多线程异步执行是很常见的开发需求,在实际开发过程中也经常用到,本篇文章将细致地讲解如何实现这一功能,包括创建多线程的方式、线程的基础操作、如何使用Java的Concurrent包以及线程安全的问题等问题。

1. 创建多线程

Java中创建多线程的方式有很多,这里主要介绍两种方式。

1.1 继承Thread类

第一种方式就是继承Thread类,并重写run方法。代码示例如下:

public class MyThread extends Thread {

    @Override
    public void run() {
        // 这里是线程执行的逻辑
    }
}

// 将线程启动
MyThread myThread = new MyThread();
myThread.start();

1.2 实现Runnable接口

第二种方式是实现Runnable接口,并将该接口实现类的实例作为参数传入Thread类的构造方法中。代码示例如下:

public class MyRunnable implements Runnable {

    @Override
    public void run() {
        // 这里是线程执行的逻辑
    }
}

// 将线程启动
MyRunnable myRunnable = new MyRunnable();
Thread thread = new Thread(myRunnable);
thread.start();

以上两种方式的区别是什么呢?对于第一种方式,我们需要重写Thread类中的run方法,在该方法中实现线程逻辑;而对于第二种方式,我们需要将Runnable接口实现类的实例传入Thread类的构造方法中,在该接口的run方法中实现线程逻辑。从某种程度上来说,第二种方式更加面向对象,因为它将线程逻辑从Thread类中抽离出来,更加符合面向对象的设计原则。

2. 线程的基本操作

Java中,线程作为程序中的执行单元,具有很多的基本操作,比如线程的启动、挂起、唤醒和终止等。

2.1 线程的启动

对于继承了Thread类的自定义线程,我们调用start方法即可启动一个新的线程。而对于实现了Runnable接口的自定义线程,我们需要将其作为参数传入Thread构造方法中实例化一个新线程,然后调用其start方法启动线程。

2.2 线程的挂起和唤醒

线程的挂起和唤醒可以使用suspend和resume方法来实现,但这些方法已经被废弃了,因为它们容易造成线程死锁。现在使用wait和notify方法来实现线程的挂起和唤醒。示例如下:

class MyThread extends Thread {
    private boolean stop = false;

    // 线程运行入口
    public void run() {
        while(!stop) {
            try {
                // 线程挂起
                synchronized(this) {
                    wait();
                }
            } catch (InterruptedException e) {

            }
        }
    }

    public void stopThread() {
        stop = true;
    }

    public void continueThread() {
        synchronized(this) {
            notifyAll();
        }
    }
}

2.3 线程的终止

线程的终止可以使用stop方法来实现,但是它已经被废弃了,因为它可能会造成线程死锁。现在,我们可以在run方法中使用一个boolean类型的变量来控制线程的终止。我们在线程启动前设置该变量为false,在需要结束线程时,将其设置为true。

3. 使用Java Concurrent包

Java中提供了Concurrent包,专门用于处理多线程的问题。使用该包可实现更高效的线程并发操作。本部分将介绍Java Concurrent包中常用的类以及其使用方法。

3.1 Lock锁

在Java Concurrent包中,提供了Lock接口,实现类有ReentrantLock和ReentrantReadWriteLock。Lock锁相较于synchronized,具有更细粒度的控制能力、更好的并发性、更好的可取消性以及更灵活的顺序规定等优点。

使用Lock锁的代码如下:

Lock lock = new ReentrantLock();
lock.lock();
try {
    // 线程安全操作
} finally {
    lock.unlock();
}

使用Lock锁时,需要手动获取锁和释放锁,原则上应在finally块中执行解锁操作。

3.2 Condition条件

Condition表示某个线程持有的锁上的等待区,通过await和signal方法来实现线程挂起和唤醒。示例代码如下:

Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();

// 线程等待
try {
    lock.lock();
    condition.await();
} catch (InterruptedException e) {
    e.printStackTrace();
} finally {
    lock.unlock();
}

// 线程唤醒
try {
    lock.lock();
    condition.signalAll();
} finally {
    lock.unlock();
}

3.3 AtomicInteger

AtomicInteger是一个支持原子操作的类,它可以在并发环境中实现线程安全性。示例代码如下:

AtomicInteger ai = new AtomicInteger(0);
ai.incrementAndGet();

3.4 CountDownLatch

CountDownLatch用于控制线程等待,让某些线程先执行,示例代码如下:

CountDownLatch countDownLatch = new CountDownLatch(5);
for(int i=0; i<5; i++) {
    new Thread(() -> {
        // 线程执行的逻辑
        countDownLatch.countDown(); // 线程执行完成
    }).start();
}
countDownLatch.await();  // 等待所有线程执行完成

4. 线程安全

在多线程编程中,当多个线程同时访问一个共享资源时,容易造成线程安全问题。线程安全问题包括以下几种:

  1. 临界区问题:多个线程同时访问一个共享资源,并对其进行修改,导致变量不一致的情况。
  2. 死锁问题:多个线程互相等待对方释放资源的情况。
  3. 非线程安全对象:某些对象在多线程环境下不能确保线程安全。

针对这些问题,我们可以使用锁、原子类、并发容器等方式来解决。

5. 示例说明

下面通过两个具体的示例,分别说明如何使用多线程实现异步执行操作。

5.1 示例一:查询多个网站的响应时间

该示例使用Java中的HttpURLConnection类来发起多个Web请求并获取其响应时间,可以用于查询多个网站的性能。

首先,我们定义一个线程类WebCheckThread,重写run方法,执行Web请求并记录响应时间。

public class WebCheckThread extends Thread {
    private String url;
    private List<Long> responseTime;

    public WebCheckThread(String url, List<Long> responseTime) {
        this.url = url;
        this.responseTime = responseTime;
    }

    @Override
    public void run() {
        long startTime = System.currentTimeMillis();
        HttpURLConnection connection = null;
        try {
            URL url = new URL(this.url);
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("HEAD");
            int responseCode = connection.getResponseCode();
            long endTime = System.currentTimeMillis();
            long time = endTime - startTime;
            responseTime.add(time);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(connection != null) {
                connection.disconnect();
            }
        }
    }
}

接着,在Main方法中,我们实例化多个WebCheckThread,并启动它们:

public static void main(String[] args) {
    String[] urls = new String[] {"http://www.baidu.com", "http://www.taobao.com", "http://www.jd.com", "http://www.am
    azon.com"};
    List<Long> responseTime = new ArrayList<>();
    for(String url : urls) {
        Thread thread = new WebCheckThread(url, responseTime);
        thread.start();
    }

    // 等待所有线程执行完成
    while(Thread.activeCount() > 2) {
        Thread.yield(); 
    }

    // 打印响应时间
    for(int i=0; i<urls.length; i++) {
        System.out.println(urls[i] + " - " + responseTime.get(i) + "ms");
    }
}

在上面的代码中,我们使用了while循环和Thread.yield()方法来等待所有线程执行完成。如果我们直接使用Thread.join()方法等待线程完成,则需要将线程的引用保存到一个线程数组中,这样代码会更加复杂。

5.2 示例二:使用线程池异步执行任务

该示例使用Java中的线程池来异步执行任务,提高任务执行效率。

首先,我们定义一个任务类Task,实现Runnable接口:

public class Task implements Runnable {
    private int taskId;

    public Task(int taskId) {
        this.taskId = taskId;
    }

    @Override
    public void run() {
        try {
            System.out.println("Task " + taskId + " is running.");
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

接着,在Main方法中,我们实例化ThreadPoolExecutor,并提交Task任务:

public static void main(String[] args) {
    ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100));

    for(int i=0; i<20; i++) {
        Task task = new Task(i);
        executor.submit(task);
    }

    executor.shutdown();
}

在上面的代码中,我们使用ThreadPoolExecutor来创建线程池,并提交了20个Task任务,最后调用shutdown方法关闭线程池。

总结

本篇文章对Java创建多线程异步执行实现代码作出了详细的解释,主要包含了创建多线程的方式、线程的基础操作、Java Concurrent包以及线程安全的问题等方面的内容。通过两个示例,我们了解了如何使用多线程实现异步执行操作,包括查询多个网站的响应时间和使用线程池异步执行任务。希望本文能对读者在日常开发中解决多线程问题有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java创建多线程异步执行实现代码解析 - Python技术站

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

相关文章

  • 每日六道java新手入门面试题,通往自由的道路–多线程

    每日六道java新手入门面试题,通往自由的道路–多线程攻略 简介 本文介绍了如何解决“每日六道java新手入门面试题,通往自由的道路–多线程” 中的六道题目,帮助初学者掌握多线程的概念和使用方法。 题目简介 本题目分为六道题目,主要涉及以下内容: 线程的创建和启动 共享变量的问题 线程安全的问题 线程池的概念和使用方法 解题思路 1. 计数器 题目描述:…

    多线程 2023年5月17日
    00
  • 举例讲解Java中的多线程编程

    让我们来详细讲解Java中的多线程编程。 如何创建线程 Java中的多线程编程是通过创建线程来实现的。而创建线程有两种方式: 继承Thread类 public class MyThread extends Thread { @Override public void run() { // 线程的逻辑 } } 实现Runnable接口 public class…

    多线程 2023年5月17日
    00
  • GO使用Mutex确保并发程序正确性详解

    GO使用Mutex确保并发程序正确性详解 在Go中,使用goroutine实现并发非常方便,但在并发程序中,很容易出现竞争条件,导致程序出现错误。所以为了确保并发程序的正确性,需要使用互斥锁(Mutex)。 什么是Mutex Mutex是Go语言中用于同步访问共享资源的机制。它可以保证在同一时间只有一个goroutine可以访问共享资源,其他goroutin…

    多线程 2023年5月17日
    00
  • java线程池合理设置最大线程数和核心线程数方式

    下面是Java线程池合理设置最大线程数和核心线程数的完整攻略: 1. 什么是线程池以及为什么要使用线程池 线程池是一种多线程编程的技术,它可以通过复用已经创建好的线程来处理新的任务,从而降低线程实例的创建和销毁所带来的开销。使用线程池可以优化多线程应用程序的性能,防止在系统资源有限的情况下过度创建线程,导致系统性能下降,甚至崩溃。 2. 如何合理设置线程池的…

    多线程 2023年5月16日
    00
  • 了解Java多线程的可见性与有序性

    了解Java多线程的可见性与有序性 可见性 在Java多线程中,可见性问题是指当多个线程访问共享数据时,其中一个线程对数据进行了修改,导致其他线程无法立即看到这个修改的结果。 原因 可见性问题的产生是因为java内存模型中存在主内存和工作内存的缓存机制,不同的线程可能会将共享数据拷贝到自己的工作内存中进行修改,修改后的结果,在没有及时写回主内存的情况下,其他…

    多线程 2023年5月17日
    00
  • Go语言并发模型的2种编程方案

    Go语言是一门支持并发编程的编程语言,它的并发模型让程序员可以利用多核CPU的优势进行高效的并发编程,提高程序性能。在Go语言中,可以使用goroutine和channel实现并发。下面,我们来详细讲解Go语言并发模型的2种编程方案。 方案1:使用Goroutine实现并发 Goroutine是Go语言提供的一种轻量级的并发机制,它可以在单个线程内同时运行多…

    多线程 2023年5月17日
    00
  • 带你快速搞定java多线程(4)

    关于“带你快速搞定Java多线程(4)”这篇文章,下面我来给你详细讲解: 首先,这篇文章主要是讲解Java多线程中的线程池使用,包括线程池的定义、创建、使用和销毁等方面。下面从以下几个方面来介绍。 一. 线程池的定义 线程池是用于存放线程的池子,专门用于管理线程的创建、销毁和复用等工作。在Java程序中,线程池可以通过ThreadPoolExecutor类实…

    多线程 2023年5月17日
    00
  • Python多线程threading模块用法实例分析

    下面我来详细讲解一下“Python多线程threading模块用法实例分析”的攻略。 简介 Python是一门高级编程语言,它在处理大规模数据时十分高效。Python标准库中提供了threading模块,可以在Python中实现多线程编程。多线程的运用可以提高程序的并行度,从而加快程序的运行速度,特别是在处理大规模数据时特别有效。 线程创建 在Python中…

    多线程 2023年5月16日
    00
合作推广
合作推广
分享本页
返回顶部