浅谈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日

相关文章

  • C#调用易语言写的Dll文件方法

    C# 调用易语言写的DLL文件有两种方式:使用DllImport特性和使用COM组件。下面详细讲解这两种方法的完整攻略。 DllImport 编写易语言DLL 在易语言中编写函数代码。 在函数顶部添加 #dllexport 命令。 在函数返回值的数据类型前加上 #stdcall 命令。 将函数编译为DLL文件。 以下为示例代码,函数名称为 Add ,返回类型…

    C# 2023年6月7日
    00
  • Unity3D实现虚拟按钮控制人物移动效果

    下面是“Unity3D实现虚拟按钮控制人物移动效果”的完整攻略: 需求分析 我们需要实现一个虚拟按钮,用于控制人物的移动效果,包括角色的左右移动和跳跃功能。 环境配置 首先需要创建一个Unity项目,并导入角色和场景资源。接着创建一个空的GameObject,命名为“UI”。在UI下创建一个Canvas,并调整Canvas的层级为第三层。 在Canvas下创…

    C# 2023年6月3日
    00
  • C# 字符串与unicode互相转换实战案例

    下面是详细讲解“C# 字符串与unicode互相转换实战案例”的完整攻略: 背景 在C#编程中,有时需要将字符串与unicode之间进行转换。本文将针对这一问题进行探讨,并提供实战案例。 技术准备 在进行转换操作前,需要先掌握以下技术: 1. 字符串类型 在C#中,字符串类型被定义为System.String类。该类型可以容纳任何Unicode字符,通常使用…

    C# 2023年6月8日
    00
  • 探秘C# 6.0 的新特性

    探秘C#6.0的新特性 C#6.0引入了一些新的语言特性,包括空值合并运算符、字符串插值、使用表达式的属性和方法、异常筛选、静态using、自动属性初始化器等。本篇文章将逐一详细介绍这些新特性。 空值合并运算符 空值合并运算符(??),是一个二元运算符,如果左操作数为空,则返回右操作数,否则返回左操作数。 示例: int? x = null; int y =…

    C# 2023年5月15日
    00
  • ASP.NET MVC获取多级类别组合下的产品

    以下是ASP.NET MVC获取多级类别组合下的产品的完整攻略: 简介 在ASP.NET MVC应用程序中,我们可能需要获取多级类别组合下的产品,例如,我们可能需要获取所有属于“电子产品”类别及其子类别的产品。在这种情况下,我们可以使用递归查询或LINQ查询获取多级类别组合下的产品。 步骤 ASP.NET MVC获取多级类别组合下的产品的步骤如下: 创建类别…

    C# 2023年5月12日
    00
  • .NET Core中的HttpClientFactory类用法详解

    HttpClientFactory是.NET Core中的一个新特性,它提供了一种更好的方式来管理和使用HttpClient实例。在本攻略中,我们将详细讲解HttpClientFactory的用法,并提供两个示例来说明它的使用。 什么是HttpClientFactory? HttpClientFactory是.NET Core 2.1中引入的一个新特性,它提…

    C# 2023年5月16日
    00
  • C#中FileStream的对比及使用方法

    C#中FileStream的对比及使用方法 什么是FileStream FileStream 是一种流(Stream),它支持在文件中读取和写入数据。FileStream 通过派生类实现了 Stream,这使得可以使用 FileStream 类来管理文件。 FileStream与其他流的比较 FileStream与StreamReader的比较 Stream…

    C# 2023年6月7日
    00
  • .NET Core配置连接字符串和获取数据库上下文实例

    在 .NET Core 中,可以使用配置文件来配置连接字符串,并使用依赖注入来获取数据库上下文实例。以下是 .NET Core 配置连接字符串和获取数据库上下文实例的完整攻略: 步骤一:创建配置文件 在 .NET Core 项目中,可以使用 appsettings.json 文件来配置连接字符串。可以在 appsettings.json 文件中添加 Conn…

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