迹忆客 专注技术分享

当前位置:主页 > 学无止境 > 编程语言 > Java >

Java 中的线程安全延迟初始化

作者:迹忆客 最近更新:2023/07/16 浏览次数:

本文将讨论在 Java 中实现线程安全的延迟初始化。


Java 中的对象初始化

延迟初始化是延迟对象创建的行为。 它还可能导致某些计算任务或首次昂贵流程的延迟。

Java 中有两种类型的对象初始化。 它们是急切初始化和惰性初始化。

在 Eager 初始化中,对象初始化发生在编译时。 如果过程很长,这会消耗时间和内存。

在延迟初始化中,对象初始化在程序需要时发生。 因此它可以节省内存、增强处理能力并提高效率。

线程是可以并行运行进程以优化时间的次要组件。 线程安全是一个 Java 类,可确保类的内部状态和函数在多个线程同时调用期间返回的值的正确性。


在 Java 中实现延迟初始化

getter 方法检查私有成员是否已经具有某些值。 如果有,该函数返回它; 否则,它会创建一个新实例并在第一次执行时返回它。

有两种方法可以进行延迟初始化。

  1. 在函数名称之前使用synchronize 关键字。
  2. 使用双重检查锁定或同步块方法。

在 Java 中编写延迟初始化的线程安全代码

当多个线程并行运行时,变量可能会返回意外结果。 这里,我们需要一个线程安全的代码来防止Java中的死锁。

例子:

考虑一家银行,其中只有一个代币计数器可用于代币分配。 这里的任务是仅当客户进来时创建一个 Bank 类; 该过程是惰性初始化。

让我们创建多个线程,例如 t1、t2 等,以了解多线程调用。 每个线程都是一个客户。

当客户来获取代币时,我们创建一个 Bank 对象,并在函数参数中使用代币编号调用 operation()。 现在,显示令牌是否可用并指定消息中的下一个操作。

如果有token,则发行token; 否则,请继续接待下一位顾客。

该程序解释了 getInstanceSynchronizedWay()getInstanceSynchronizedBlockWay()。 我们可以使用Thread.sleep来保证输出的准确性。


在Java中使用synchronized方法进行线程安全的延迟初始化

在此示例中,我们有两个客户线程。

_instance 变量检查实例是否为空。 如果变量为空,程序将创建一个实例。

空标志检查令牌是否可用。 如果令牌可用,则标志值为 true。

将令牌提供给客户后,程序将标志值设置为 false。 因此,在 operation() 完成之前,下一个客户将不会获得令牌。

示例代码:

//Helper class as a Singleton Class
class BankOperation {
    //Private variables
    private static BankOperation _instance;
    private boolean empty = false;
    private String customerName = "default"; 
    // Displays the instance only during creation
    private BankOperation()
    {
        System.out.println("Instance Creation Over\n");
    }
   //synchronized method
    public static synchronized BankOperation
    getInstanceSynchronizedWay()
    {
        if (_instance == null)
            _instance = new BankOperation(); 
        return _instance;
    }
    //Check if the token is available
    public boolean isOperationBankEmpty()
    {
        return empty;
    } 
    //When token giving is successful
    public void endOperation() {
        empty = true; 
    }
    //Multiple threads access the method below
    public synchronized void operation(String paramCust)
    {
        //When the token is available. The flag is true.
        if (empty == true) {
            customerName = paramCust;
            //Issue the token to the customer
            System.out.println("Operation - Token is available.\n" + "Giving token to - " + customerName);
            empty = false;
        }
        //The token is not available
        else {
            System.out.println("Sorry " + paramCust + ", Counter closed with " + customerName);
        }
    }
}
//Main class
public class Bank {
    //Driver function
    public static void main(String args[])
    {
        //synchronized method
        //Create a thread in main()
        Thread t1 = new Thread(new Runnable() {
            //run() for thread 1
            public void run()
            {
                //Create objects of other classes here

                BankOperation i1 = BankOperation.getInstanceSynchronizedWay();

                System.out.println("Synchronized Method - Instance 1 - " + i1 + "\n");
                    //The method with an argument
                    i1.endOperation();
                    i1.operation("Customer 1");
            }
        });
        //Thread 2
        Thread t2 = new Thread(new Runnable() {
            //run() for thread 2
            public void run()
            {
                BankOperation i2 = BankOperation.getInstanceSynchronizedWay();
                System.out.println("Synchronized Method - Instance 2 - " + i2 + "\n");
                i2.operation("Customer 2");
            }
        });
        // Starting thread 1
        t1.start();
        //Start thread 2
        t2.start();
    }
}

输出:

Instance Creation Over
Synchronized Method - Instance 1 - BankOperation@792bbbb1
Synchronized Method - Instance 2 - BankOperation@792bbbb1
Operation - Token is available.
Giving the token to - Customer 1
Sorry Customer 2, Counter closed with Customer 1

在上面的输出中,用户可以观察到两个客户实例是并行出现的。 因此,第一个实例获取令牌,第二个实例获取消息。


在 Java 中使用双重检查锁定方法进行线程安全的延迟初始化

在此示例中,我们创建两个客户线程。 _instanceForDoubleCheckLocking 变量两次检查实例是否为 null,并且方法 getInstanceSynchronizedBlockWay() 返回新实例。

标志empty的值决定了令牌的可用性。 如果该标志为真,则该令牌可供客户使用。

客户获得令牌后,该标志变为 false。 在当前线程完成其操作之前,运行多个线程无法更改任何值。

示例代码:

//Helper class
class BankOperation {
    //Private variable declaration
    private static BankOperation _instanceForDoubleCheckLocking;
    private boolean empty = false;
    private String customerName = "default"; 
    private BankOperation()
    {
        System.out.println("Instance Creation Over\n");
    }
    //Synchronized Block Method or Double-Checked Locking
    public static BankOperation
    getInstanceSynchronizedBlockWay()
    {
        //Check double locking

        if (_instanceForDoubleCheckLocking == null)
            synchronized (BankOperation.class)
            {
                if (_instanceForDoubleCheckLocking == null)
                    _instanceForDoubleCheckLocking = new BankOperation();
            }
        return _instanceForDoubleCheckLocking;
    }
    //The `token` availability check
    public boolean isOperationBankEmpty()
    {
        return empty;
    } 
    //After giving the token set the flag value
    public void endOperation() {
        empty = true; 
    }
    //Multiple threads access the method below
    public synchronized void operation(String paramCust)
    {
        //The flag is true when the `token' is available
        if (empty == true) {
            customerName = paramCust;
            //Give the `token` to the customer
            System.out.println("Operation - Token is available.\n" + "Giving token to - " + customerName);
            empty = false;
        }
        //When the `Token` is not available
        else {
            System.out.println("Sorry " + paramCust + ", Counter closed with " + customerName);
        }
    }
}
//Main class
public class Bank {
    //Driver function
    public static void main(String args[])
    {
       //Double Checked Locking
        System.out.println("Double Checked locking - Synchronized Block");
        //Thread 3
        Thread t3 = new Thread(new Runnable() {
            //run() for thread 3
            public void run()
            {
                BankOperation i1 = BankOperation.getInstanceSynchronizedBlockWay();
                System.out.println("Double Checked Locking - Instance 1 - " + i1 + "\n"); 

                i1.endOperation();
                i1.operation("Customer 1");
            }
        });
        //Thread 4
        Thread t4 = new Thread(new Runnable() {
            //run() for thread 4
            public void run()
            {
                BankOperation i2 = BankOperation.getInstanceSynchronizedBlockWay();
                System.out.println("Double Checked Locking - Instance 2 - " + i2 + "\n"); 
                i2.operation("Customer 2");
            }
        });
        t3.start();
        t4.start();
    }
}

输出1:

Double Checked locking - Synchronized Block
Instance Creation Over
Double Checked Locking - Instance 1 - BankOperation@1efc89d6
Double Checked Locking - Instance 2 - BankOperation@1efc89d6
Operation - Token is available.
Giving  token to - Customer 1
Sorry Customer 2, Counter closed with Customer 1

请注意,当两个客户实例并行到达时,程序将令牌提供给第一个实例并通知第二个客户。

输出2:

Double Checked locking - Synchronized Block
Instance Creation Over
Double Checked Locking - Instance 2 - BankOperation@282416b6
Double Checked Locking - Instance 1 - BankOperation@282416b6
Sorry Customer 2, the counter closed with the default
Operation - Token is available.
Giving Bank token to - Customer 1

这里,token对于客户2来说是不可用的,原因是在 operation() 之前缺少 endOperation()。 客户 1 获得令牌,因为 endOperation()operation() 之前运行。

本教程教给我们两种在 Java 中实现线程安全延迟初始化的方法。 第一种方法使用 synchronized 关键字,第二种方法是 synchronized 块方法。

同步块方法确保了双重检查。 用户可以根据上下文选择任何一种方式。

转载请发邮件至 1244347461@qq.com 进行申请,经作者同意之后,转载请以链接形式注明出处

本文地址:

相关文章

在 Java 中对一个 Switch Case 语句使用多个值

发布时间:2023/07/16 浏览次数:172 分类:Java

在本文中,我们将学习如何在一个 switch-case 语句中使用多个值。使用 switch-case 语句 Java 允许程序员通过使用 switch case 语句来像其他编程语言一样克服太多的 if-else 条件语句。

Java 聚合与组合

发布时间:2023/07/16 浏览次数:67 分类:Java

在Java中,聚合和组合是紧密相连的两个概念。 组合是类之间的紧密关联,而聚合是弱关联。Java 中的组合 Java 中的聚合

Java 错误 Java.Security.InvalidKeyException: Illegal Key Size

发布时间:2023/07/15 浏览次数:98 分类:Java

本篇文章介绍包含 java.security.InvalidKeyException: Illegal key size 的 Java 代码。 然后,我们将了解其可能的原因。最后,它通过消除指定的错误来引导我们找到解决方案。

扫一扫阅读全部技术教程

社交账号
  • https://www.github.com/onmpw
  • qq:1244347461

最新推荐

教程更新

热门标签

扫码一下
查看教程更方便