Java 简明教程

Java - Block Synchronization

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

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

Block Synchronization in Java

Java 编程语言提供了一种非常方便的方法来创建线程并 synchronizing使用同步块来完成它们的任务。您保留此块内的共享资源。

Syntax

以下是同步语句的一般形式 −

synchronized(objectidentifier) {
   // Access shared variables and other shared resources
}

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

Multithreading Example without Synchronization

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

Example

package com.tutorialspoint;

class PrintDemo {
   public void printCount() {
      try {
         for(int i = 5; i >  0; i--) {
            Thread.sleep(50);
            System.out.println("Counter   ---   "  + i );
         }
      } catch (Exception e) {
         System.out.println("Thread  interrupted.");
      }
   }
}

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

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

   public void run() {
      printDemo.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 printDemo = new PrintDemo();

      ThreadDemo t1 = new ThreadDemo( "Thread - 1 ", printDemo );
      ThreadDemo t2 = new ThreadDemo( "Thread - 2 ", printDemo );

      t1.start();
      t2.start();

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

Output

每次运行该程序都会产生不同的结果——

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

Multithreading Example with Synchronization at Block level

以下是按顺序打印计数器值的示例,每次运行都会产生相同的结果。我们在一个块上放置了 synchronized 关键字,以便在方法执行期间计数器递增代码现在按对象锁定。我们使用当前对象作为锁,将其作为参数传递给同步块。

Example

package com.tutorialspoint;

class PrintDemo {
   public void printCount() {
      try {
         for(int i = 5; i > 0; i--) {
            Thread.sleep(50);
            System.out.println("Counter   ---   "  + i );
         }
      } catch (Exception e) {
         System.out.println("Thread  interrupted.");
      }
   }
}

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

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

   public void run() {
      synchronized(printDemo) {
         printDemo.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 printDemo = new PrintDemo();

      ThreadDemo t1 = new ThreadDemo( "Thread - 1 ", printDemo );
      ThreadDemo t2 = new ThreadDemo( "Thread - 2 ", printDemo );

      t1.start();
      t2.start();

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

Output

每次运行此程序都会产生相同的结果 −

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.

Multithreading Example with Synchronization at Method level

这是一个在每次运行时都会按顺序打印 counter 值的示例,而且每次都产生相同的结果。这次,我们在一个方法上放了 synchronized 关键字,因此在方法执行期间,整个方法会按照对象锁定。

Example

package com.tutorialspoint;

class PrintDemo extends Thread {
   public void printCount() {
      try {
         for(int i = 5; i > 0; i--) {
            Thread.sleep(50);
            System.out.println("Counter --- " + i );
         }
      } catch (Exception e) {
         System.out.println("Thread " + Thread.currentThread().getName()+" interrupted.");
      }
   }
   public synchronized void run() {
      printCount();
      System.out.println("Thread " + Thread.currentThread().getName() + " exiting.");
   }
}
public class TestThread {
   public static void main(String args[]) {
      PrintDemo printDemo = new PrintDemo();
      Thread t1 = new Thread(printDemo );
      Thread t2 = new Thread(printDemo );
      t1.start();
      t2.start();
      // wait for threads to end
      try {
         t1.join();
         t2.join();
      } catch ( Exception e) {
         System.out.println("Interrupted");
      }
   }
}

Output

每次运行此程序都会产生相同的结果 −

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.