当前位置: 首页 > 编程笔记 >

Java中的同步关键字

宇文飞翮
2023-03-14
本文向大家介绍Java中的同步关键字,包括了Java中的同步关键字的使用技巧和注意事项,需要的朋友参考一下

当我们在程序中启动两个或多个线程时,可能会出现多个线程尝试访问同一资源,最终由于并发问题,它们可能产生无法预料的结果的情况。例如,如果多个线程试图在同一文件中写入数据,则它们可能会破坏数据,因为其中一个线程可以覆盖数据,或者一个线程同时打开同一文件时,另一个线程可能正在关闭同一文件。

因此,需要同步多个线程的操作,并确保在给定的时间点只有一个线程可以访问资源。这是使用称为Monitors的概念实现的。Java中的每个对象都与一个监视器关联,线程可以锁定或解锁监视器。一次只能有一个线程在监视器上保持锁。

Java编程语言提供了一种非常方便的方式来创建线程并通过使用同步块来同步其任务。您将共享资源保留在此块内。以下是同步语句的一般形式-

语法

synchronized(objectidentifier) {
   //访问共享变量和其他共享资源
}

在这里,objectidentifier是对对象的引用,该对象的锁与同步语句表示的监视器相关联。现在,我们将看到两个示例,其中将使用两个不同的线程来打印计数器。当线程不同步时,它们将不按顺序打印计数器值,但是当我们通过放在内部synchronized()块中来打印计数器时,则对于两个线程,它将按顺序非常大量地打印计数器。

没有同步的多线程示例

这是一个简单的示例,它可以按顺序打印计数器值,也可以不按顺序打印,并且每次运行它时,它都会基于线程的CPU可用性而产生不同的结果。

示例

class PrintDemo {
   public void printCount() {
      try {
         for(int i = 5; i > 0; i--) {
            System.out.println("Counter --- " + i );
         }
      } catch (Exception e) {
         System.out.println("线程中断。");
      }
   }
}
class ThreadDemo extends Thread {
   private Thread t;
   private String threadName;
   PrintDemo PD;

   ThreadDemo( String name, PrintDemo pd) {
      threadName = name;
      PD = pd;
   }

   public void run() {
      PD.printCount();
      System.out.println("Thread " + threadName + " exiting.");
   }

   public void start () {
      System.out.println("Starting " + threadName );
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}

public class TestThread {
   public static void main(String args[]) {
      PrintDemo PD = new PrintDemo();

      ThreadDemo T1 = new ThreadDemo( "Thread - 1 ", PD );
      ThreadDemo T2 = new ThreadDemo( "Thread - 2 ", PD );

      T1.start();
      T2.start();

      //等待线程结束
      try {
         T1.join();
         T2.join();
      } catch ( Exception e) {
         System.out.println("Interrupted");
      }
   }
}

每次您运行该程序时,都会产生不同的结果-

输出结果

Starting Thread - 1
Starting Thread - 2
Counter --- 5
Counter --- 4
Counter --- 3
Counter --- 5
Counter --- 2
Counter --- 1
Counter --- 4
Thread Thread - 1 exiting.
Counter --- 3
Counter --- 2
Counter --- 1
Thread Thread - 2 exiting.

带有同步的多线程示例

这是相同的示例,它按顺序打印计数器值,并且每次运行它时,它都会产生相同的结果。

示例

class PrintDemo {
   public void printCount() {
      try {
         for(int i = 5; i > 0; i--) {
            System.out.println("Counter --- " + i );
         }
      } catch (Exception e) {
         System.out.println("线程中断。");
      }
   }
}

class ThreadDemo extends Thread {
   private Thread t;
   private String threadName;
   PrintDemo PD;

   ThreadDemo( String name, PrintDemo pd) {
      threadName = name;
      PD = pd;
   }

   public void run() {
      synchronized(PD) {
         PD.printCount();
      }
      System.out.println("Thread " + threadName + " exiting.");
   }

   public void start () {
      System.out.println("Starting " + threadName );

      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}

public class TestThread {
   public static void main(String args[]) {
      PrintDemo PD = new PrintDemo();

      ThreadDemo T1 = new ThreadDemo( "Thread - 1 ", PD );
      ThreadDemo T2 = new ThreadDemo( "Thread - 2 ", PD );

      T1.start();
      T2.start();

      //等待线程结束
      try {
         T1.join();
         T2.join();
      } catch ( Exception e) {
         System.out.println("Interrupted");
      }
   }
}

每次您运行该程序时,都会产生相同的结果-

输出结果

Starting Thread - 1
Starting Thread - 2
Counter --- 5
Counter --- 4
Counter --- 3
Counter --- 2
Counter --- 1
Thread Thread - 1 exiting.
Counter --- 5
Counter --- 4
Counter --- 3
Counter --- 2
Counter --- 1
Thread Thread - 2 exiting.
 类似资料:
  • 这个问题以前可能已经回答过了,但是由于这个问题的复杂性,我需要一个确认。所以我重新措辞这个问题 问题1:当一个线程进入一个同步块时,内存屏障将包括被触摸的任何字段,而不仅仅是我同步的对象的字段?因此,如果在一个同步块中修改了许多对象,那么在线程内存缓存之间会有大量内存移动。 问题 2 : 在线程 1 中隐式地是“发生前”关系的一部分? 我希望是这样,但可能不是这样。如果没有,有没有一个技巧可以让它

  • 问题内容: c#是否具有自己的java“ synchronized”关键字版本? 即在Java中,可以将其指定为函数,对象或代码块,如下所示: 要么 问题答案: 首先-大多数类将永远不需要是线程安全的。使用YAGNI:仅当你知道实际上将要使用它(并对其进行测试)时,才应用线程安全性。 对于方法级的东西,有: 这也可以用于访问器(属性和事件): 请注意,默认情况下,类似字段的事件是同步的,而自动实现

  • 问题内容: 所以我正在用关键字测试。这是我尝试的示例: 当我运行它时,来自两个线程的调用方法的输出生成以下输出: 当我将方法更改为: 我得到以下输出: 尽管这使我清楚地了解的目的,但我想知道还有其他可以使用的原因。还是我在这里所做的,是为什么我们需要使用此关键字的唯一原因? 谢谢。 编辑: 令我感到困惑的另一件事是,在第一个输出中,为什么计数器在7之后变为3。这对我来说似乎有点不可能,但是每次尝试

  • 问题内容: 假设我有以下Java代码 同步是否会阻止重新排序?a,b和c之间没有依赖关系。先分配给b然后再分配给c?如果我还没有同步,则可以用JVM选择的任何方式对语句重新排序? 问题答案: 同步是否会阻止重新排序? 它可以防止重新排序。您仍然可以在同步块外部和同步块内部进行重新排序,但不能从同步块内部对其进行重新排序。 a,b和c之间没有依赖关系。 没关系。 先分配给b然后再分配给c? 是。但是

  • 本文向大家介绍Java中synchronized关键字修饰方法同步的用法详解,包括了Java中synchronized关键字修饰方法同步的用法详解的使用技巧和注意事项,需要的朋友参考一下 Java的最基本的同步方式,即使用synchronized关键字来控制一个方法的并发访问。 每一个用synchronized关键字声明的方法都是临界区。在Java中,同一个对象的临界区,在同一时间只有一个允许被访

  • 问题内容: 在Java中,在代码中声明关键部分的惯用方式如下: 几乎所有块都在上同步 ,但这是否有特定原因?还有其他可能性吗?是否有关于同步对象的最佳实践?(例如?的私有实例) 问题答案: 首先,请注意以下代码段是相同的。 和: 做 完全一样的事情 。除了代码的可读性和样式之外,它们都不是其中之一。 当您同步方法或代码块时,重要的是要知道 为什么 要这样做,要锁定的 对象 到底是 什么,目的 是