Java线程同步

时间:2020-02-23 14:37:16  来源:igfitidea点击:

本文讨论了Java中线程同步的重要性以及如何在程序中实现线程同步。

当程序有多个线程时,当不同的线程试图访问同一资源或者同时执行相同的操作时,可能会出现问题。这种情况会导致错误和并发问题。让我们举一个例子,程序中有两个线程试图读/写一个文本文件。当两个线程都在写文件时,一个线程的数据可能被另一个线程重写,在读取文件时也会发现相同的问题。

因此,线程同步是必要的,以便多个线程在任何给定时间点一次访问同一个资源。

为什么要使用线程同步?

  • 防止螺纹干涉

  • 避免一致性问题和并发性问题

  • 防止数据丢失

有两种类型的线程同步互斥和线程间通信。

  • 互斥

  • 同步方法。

  • 同步块。

  • 静态同步。

  • 协作(java中的线程间通信)

同步块

同步块用于线程同步。

Synchronized关键字用于标识Java中的同步块,并基于某个对象进行同步。这背后的主要概念是,在同一对象上同步的所有同步块一次只能有一个线程其中执行,从而防止多个线程同时运行和执行。所有其他试图进入同步块的线程将被阻塞,直到同步块中的线程退出该块。

共享资源保存在这个同步块中,这样在给定的时间点上只有一个线程可以访问特定的资源。

同步块的语法如下所示:

synchronized(referencetoobject) {
 //Shared variables and other shared resources are placed here
}

监视器

在试图理解和实现Java中的同步时,监视器的概念非常重要。

Java中的每个对象都与一个监视器相关联

线程可以锁定或者解锁监视器

在给定的时间内,只有一个线程可以拥有一个监视器。

一次只能有一个线程持有监视器上的锁

线程同步示例

//We write a program with a simple counter execution.
class Countings {
 public void printing() {
    try {
       for(int i = 5; i > 0; i--) {
          System.out.println( i );
       }
    } catch (Exception e) {
       System.out.println("Thread  interrupted.");
    }
 }
}

class Threadings extends Thread {
 private Thread thrd;
 private String thrdName;
 Countings gg;

 Threadings( String name,  Countings abc) {
    thrdName = name;
    gg = abc;
 }
  public void run() {
    gg.printing();
    System.out.println("Thread " +  thrdName + " exiting.");
 }

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

public class Tests {
 public static void main(String args[]) {

    Countings gg = new Countings();

    Countings T1 = new Countings ( "Thread - 1 ", gg );
    Countings T2 = new Countings ( "Thread - 2 ", gg );

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

    //threads take some time to end
       try {
       T1.join();
       T2.join();
    } catch ( Exception e) {
       System.out.println("Interrupted");
    }
 }
}

输出:(每次运行产生不同的结果)

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

同一个示例,但这次是线程同步:

class Countings {
 public void printings() {
    try {
       for(int i = 5; i > 0; i--) {
          System.out.println( i );
       }
    } catch (Exception e) {
       System.out.println("Thread  interrupted.");
    }
 }
}
class Threadings extends Thread {
 private Thread t;
 private String thrdName;
 Countings  gg;

 Threadings( String name,  Countings abc) {
    thrdName = name;
    gg = abc;
 }

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

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

public class Testings{

 public static void main(String args[]) {
    Countings gg = new Countings();

    Threadings T1 = new Threadings ( "Thread - 1 ", gg );
    Threadings T2 = new Threadings ( "Thread - 2 ", gg );

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

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

输出:(我们可以看到输出是同步的,每次执行程序时都是相同的)

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