Java多线程中的同步问题

举报
从大数据到人工智能 发表于 2022/03/28 00:43:23 2022/03/28
【摘要】 多线程程序可能经常遇到多个线程尝试访问相同资源并最终产生错误和无法预料的结果的情况。因此需要通过某种同步方法确保在给定时间点只有一个线程可以访问资源。 Java 提供了一种使用同步块创建线程和同步它们的任务的方法。 Java 中的同步块用 synchronized 关键字标记。 Java 中的同步块在某个对象上同步。 在同一个对象上同步的所有同步块一次只能在其中执行一个线程。 所有其他试图进...

多线程程序可能经常遇到多个线程尝试访问相同资源并最终产生错误和无法预料的结果的情况。

因此需要通过某种同步方法确保在给定时间点只有一个线程可以访问资源。 Java 提供了一种使用同步块创建线程和同步它们的任务的方法。 Java 中的同步块用 synchronized 关键字标记。 Java 中的同步块在某个对象上同步。 在同一个对象上同步的所有同步块一次只能在其中执行一个线程。 所有其他试图进入同步块的线程都被阻塞,直到同步块内的线程退出该块。

以下是同步块的一般形式:

// Only one thread can execute at a time. 
// sync_object is a reference to an object
// whose lock associates with the monitor. 
// The code is said to be synchronized on
// the monitor object
synchronized(sync_object)
{
   // Access shared variables and other
   // shared resources
}

这种同步是在 Java 中通过一个称为监视器的概念实现的。 在给定时间只有一个线程可以拥有一个监视器。 当一个线程获得一个锁时,就说它已经进入了监视器。 所有其他试图进入锁定监视器的线程都将被挂起,直到第一个线程退出监视器。

以下是带同步的多线程示例。

// A Java program to demonstrate working of
// synchronized.

import java.io.*;
import java.util.*;

// A Class used to send a message
class Sender
{
  public void send(String msg)
  {
    System.out.println("Sending\t" + msg );
    try
    {
      Thread.sleep(1000);
    }
    catch (Exception e)
    {
      System.out.println("Thread interrupted.");
    }
    System.out.println("\n" + msg + "Sent");
  }
}

// Class for send a message using Threads
class ThreadedSend extends Thread
{
  private String msg;
  Sender sender;

  // Receives a message object and a string
  // message to be sent
  ThreadedSend(String m, Sender obj)
  {
    msg = m;
    sender = obj;
  }

  public void run()
  {
    // Only one thread can send a message
    // at a time.
    synchronized(sender)
    {
      // synchronizing the snd object
      sender.send(msg);
    }
  }
}

// Driver class
class SyncDemo
{
  public static void main(String args[])
  {
    Sender snd = new Sender();
    ThreadedSend S1 =
      new ThreadedSend( " Hi " , snd );
    ThreadedSend S2 =
      new ThreadedSend( " Bye " , snd );

    // Start two threads of ThreadedSend type
    S1.start();
    S2.start();

    // wait for threads to end
    try
    {
      S1.join();
      S2.join();
    }
    catch(Exception e)
    {
      System.out.println("Interrupted");
    }
  }
}

输出

Sending     Hi 

 Hi Sent
Sending     Bye 

 Bye Sent

每次我们运行程序时,输出都是相同的。

在上面的例子中,我们选择在 ThreadedSend 类的 run() 方法中同步 Sender 对象。 或者,我们可以将整个 send() 块定义为同步的,产生相同的结果。 然后我们不必在 ThreadedSend 类的 run() 方法中同步 Message 对象。

// An alternate implementation to demonstrate
// that we can use synchronized with method also.

class Sender {
   public synchronized void send(String msg)
   {
       System.out.println("Sending\t" + msg);
       try {
           Thread.sleep(1000);
       }
       catch (Exception e) {
           System.out.println("Thread interrupted.");
       }
       System.out.println("\n" + msg + "Sent");
   }
}

我们不必总是同步整个方法。 有时最好只同步方法的一部分。 方法中的 Java 同步块可以实现这个目的。

// One more alternate implementation to demonstrate
// that synchronized can be used with only a part of  
// method

class Sender  
{
   public void send(String msg)
   {
       synchronized(this)
       {
           System.out.println("Sending\t" + msg );
           try  
           {
               Thread.sleep(1000);
           }  
           catch (Exception e)  
           {
               System.out.println("Thread interrupted.");
           }
           System.out.println("\n" + msg + "Sent");
       }
   }
}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。