浅谈Java多线程实现及同步互斥通讯

浅谈Java多线程实现及同步互斥通讯

引言

多线程是指一种多个线程执行完毕后可以得到更好的系统性能的机制。Java多线程的实现是通过创建Thread实例或者继承Thread类并重写它的run()方法来完成的。Java也提供了一个Java.util.concurrent包,它为Java多线程编程提供了更多的助力。在多线程编程中,同步互斥是一种非常重要的问题,它可以确保多个线程协同工作时不会出现死锁、竞态条件和其它不安全的情况。

Java多线程实现

通过继承Thread类实现

下面这个例子演示了如何通过继承Thread类来实现多线程。

class MyThread extends Thread {
    @Override
    public void run() {
        // 这里可以放置线程的任务代码
    }
}

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

通过运行TestMyThread类,该程序会创建一个新的线程并开始运行。

通过Runnable接口实现

下面这个例子演示了如何通过实现Runnable接口来实现多线程。

class MyRunnable implements Runnable {
    @Override
    public void run() {
        // 这里可以放置线程的任务代码
    }
}

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

通过运行TestMyRunnable类,该程序会创建一个新的线程并开始运行。

同步互斥

当多个线程访问共享资源时,就有可能会出现多个线程访问同一资源的情况,这时就需要同步互斥来保护共享资源。Java提供了两种方法来实现同步互斥:synchronized关键字和Lock接口。

synchronized关键字

我们可以使用synchronized关键字来保护代码块或者方法,使得多个线程必须获得锁才能执行这个代码块或方法。下面是一个使用synchronized关键字的例子。

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

public class TestCounter {
    public static void main(String[] args) {
        Counter counter = new Counter();
        // 创建多线程对计数器进行操作
    }
}

上面的代码创建了一个计数器类,接着我们在Counter类的increment()、decrement()和getCount()方法上都加上了synchronized关键字。这样就可以保证在多个线程同时访问这些方法时,只有一个线程可以获得锁并执行方法,其它线程则必须等待。

Lock接口

另外一种实现同步互斥的方式是使用Lock接口。与synchronized关键字不同的是,Lock接口使用时需要程序员主动获取锁和释放锁。下面是一个使用Lock接口的例子。

class Counter {
    private int count = 0;
    private Lock lock = new ReentrantLock();
    public void increment() {
        lock.lock();
        try {
            count++;
        } finally {
            lock.unlock();
        }
    }
    public void decrement() {
        lock.lock();
        try {
            count--;
        } finally {
            lock.unlock();
        }
    }
    public int getCount() {
        return count;
    }
}

public class TestCounter {
    public static void main(String[] args) {
        Counter counter = new Counter();
        // 创建多线程对计数器进行操作
    }
}

上面的代码创建了一个计数器类,接着我们在Counter类中添加了一个Lock接口类型的成员变量lock。然后在increment()、decrement()方法中使用lock.lock()获取锁,并在finally块中使用lock.unlock()释放锁。这样就可以保证每个线程进入这个方法时必须先获得锁,如果没有得到锁则线程进入等待状态。

示例

示例1:线程安全的懒汉式单例模式

public class Singleton {
    private static Singleton instance;
    private static Lock lock = new ReentrantLock();
    private Singleton() {}
    public static Singleton getInstance() {
        if (instance == null) {
            lock.lock();
            try {
                if (instance == null) {
                    instance = new Singleton();
                }
            } finally {
                lock.unlock();
            }
        }
        return instance;
    }
}

上面的代码实现了一个线程安全的懒汉式单例模式。在getInstance()方法中我们使用了Lock接口来实现同步互斥,确保在多个线程同时获取单例对象时不会出现问题。

示例2:多线程实现带判断Condition的生产者消费者模式

public class ProduceConsume {
    private LinkedList<Integer> list = new LinkedList<>();
    private Lock lock = new ReentrantLock();
    private Condition notFull = lock.newCondition();
    private Condition notEmpty = lock.newCondition();
    private final int MAXSIZE = 5;
    public void produce() {
        lock.lock();
        try {
            while (list.size() == MAXSIZE) {
                notFull.await();
            }
            int num = new Random().nextInt(10);
            list.add(num);
            System.out.println("生产者生产了" + num);
            notEmpty.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
    public void consume() {
        lock.lock();
        try {
            while (list.size() == 0) {
                notEmpty.await();
            }
            int num = list.removeFirst();
            System.out.println("消费者消费了" + num);
            notFull.signalAll();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}

上面的代码实现了一个带判断Condition的生产者消费者模式。使用Lock接口的实例的Condition对象,使生产者要在容器满的时候停止生产,并等待消费者来消费;消费者要在容器空的时候停止消费,并等待生产者来生产。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:浅谈Java多线程实现及同步互斥通讯 - Python技术站

(0)
上一篇 2023年6月7日
下一篇 2023年6月7日

相关文章

  • .NET使用DinkToPdf将HTML转成PDF的示例代码

    让我来给您详细讲解下“.NET使用DinkToPdf将HTML转成PDF的示例代码”的攻略吧。 什么是DinkToPdf DinkToPdf是一个开源的跨平台库,可以将HTML转换为PDF文档。它使用WKHtmlToPdf底层转换引擎,支持Windows,Linux和MacOS。 安装DinkToPdf 要使用DinkToPdf,您需要将它作为NuGet包添…

    C# 2023年6月3日
    00
  • C#使用windows服务发送邮件

    下面是详细讲解C#使用Windows服务发送邮件的完整攻略。 1. 什么是Windows服务发送邮件 Windows服务是在后台运行的应用程序,它没有界面和交互,但是可以在指定的时间执行预定义的任务。Windows服务发送邮件是指利用Windows服务应用程序实现设置好相关参数后,程序将会在固定的时间自动发送邮件。 2. 基本步骤 Windows服务发送邮件…

    C# 2023年5月31日
    00
  • C#全角半角转换函数代码分享

    C#全角半角转换函数代码分享 在C#开发中,我们经常会遇到需要将字符串中的全角字符转换为半角字符,或者将半角字符转换为全角字符的需求。为了方便开发,我们可以编写一个函数来完成这个任务。 函数说明 以下是一个C#中的全角半角字符转换函数代码: public static string Convert(string text, bool toDBC) { cha…

    C# 2023年6月7日
    00
  • c# 基于任务的异步编程模式(TAP)的异常处理

    当使用基于任务的异步编程模式(TAP)开发 c# 应用程序时,我们经常需要处理异步操作中的异常。本文将为您详细介绍如何在 TAP 中处理异常,以及如何通过示例代码演示异常处理。 TAP 中异常处理的重要性 在 c# 的 TAP 开发中,使用异步方法执行操作已经成为一个常见的操作。但是,异步操作可能会出现异常,并且如果不正确处理会导致意想不到的结果。 在 TA…

    C# 2023年5月14日
    00
  • nodejs中sleep功能实现暂停几秒的方法

    要在Node.js中实现sleep功能即暂停几秒的效果,常用的方法是使用setInterval函数进行定时执行。以下是步骤: 步骤1:编写sleep函数 编写一个sleep函数,该函数接收一个参数(单位为milliseconds),等待给定时间后返回。 function sleep(ms) { return new Promise((resolve) =&g…

    C# 2023年6月6日
    00
  • C# 7.0 使用下划线忽略使用的变量的原因分析

    C#7.0使用下划线忽略使用的变量的原因分析 在C#7.0中,我们可以使用一个特殊的下划线符号(_)来忽略我们不需要使用的变量,这在代码中并不会引起编译器的警告或错误提示,那么为什么需要使用这个符号,本文将对此进行详细讲解。 忽略变量的原因 在我们的应用程序和代码中,常常会出现我们所不需要的变量、返回值或者方法参数,但在某种情况下,我们又不得不使用这些变量或…

    C# 2023年5月15日
    00
  • C#在LINQ中使用GroupBy

    接下来我将为你讲解C#在LINQ中使用GroupBy的完整攻略。 1. 概述 在LINQ中,我们可以使用GroupBy方法对数据进行分组,GroupBy方法返回一个IEnumerable类型的集合,其中TKey是分组的条件,TSource是分组的元素。在Grouping中,有一个Key属性,用于获取当前分组的键。在分组之后,我们还可以使用Aggregate、…

    C# 2023年6月1日
    00
  • c# 单例模式的实现

    当在 C# 中开发应用程序时,善于使用设计模式是非常重要的。单例模式是一种常用的模式,它用于确保一个类只有一个实例,并提供全局访问点。 以下是实现单例模式的典型步骤: 步骤一:声明一个私有的构造函数 单例模式的首要目标是保证一个类只创建一个对象,并允许客户端代码访问实例。为了控制类的实例化,需要阻止类外部的代码调用构造函数。可以通过将构造函数的访问权限设置为…

    C# 2023年5月31日
    00
合作推广
合作推广
分享本页
返回顶部