详解Java如何实现线程同步

发布时间:2020-07-18 16:51:59 作者:小猪
来源:亿速云 阅读:112

小编这次要给大家分享的是详解Java如何实现线程同步,文章内容丰富,感兴趣的小伙伴可以来了解一下,希望大家阅读完这篇文章之后能够有所收获。

一、概述

无论是什么语言,在多线程编程中,常常会遇到多个线同时操作程某个变量(读/写),如果读/写不同步,则会造成不符合预期的结果。

例如:线程A和线程B并发运行,都操作变量X,若线程A对变量X进行赋上一个新值,线程B仍然使用变量X之前的值,很明显线程B使用的X不是我们想要的值了。

Java提供了三种机制,解决上述问题,实现线程同步:

同步代码块

synchronized(锁对象){
	// 这里添加受保护的数据操作
}

同步方法

静态同步方法:synchronized修饰的静态方法,它的同步锁是当前方法所在类的字节码对象

public static synchronized void staticMethod(){
}

非静态同步方法:synchronized修饰的非静态方法,它的同步锁即为this

public synchronize void method(){
}

锁机制

// 以可重入锁举例
Lock lock = new ReentrantLock(/*fail*/);
// fail:
// true表示使用公平锁,即线程等待拿到锁的时间越久,越容易拿到锁
// false表示使用非公平锁,线程拿到锁全靠运气。。。cpu时间片轮到哪个线程,哪个线程就能获取锁
lock.lock();
// 这里添加受保护的数据操作
lock.unlock();

个人理解:其实无论哪种机制实现线程同步,本质上都是加锁->操作数据->解锁的过程。同步代码块是针对{}中,同步方法是针对整个方法。其ReentrantLock类提供的lock和unlock和C++的std::mutex提供lock和unlock类似

二、测试用例

详解Java如何实现线程同步

同步代码块测试类

package base.synchronize;


public class SynchronizeBlock implements Runnable {
  private int num = 100;

  @Override
  public void run() {
    while (num > 1) {
      synchronized (this) {
        // 同步代码块,只有拿到锁,才有cpu执行权
        System.out.println("Thread ID:" + Thread.currentThread().getId() + "---num:" + num);
        num--;
      }
    }
    System.out.println("Thread ID:" + Thread.currentThread().getId() + " exit");
  }
}

同步方法测试类

package base.synchronize;

public class SynchronizeMethod implements Runnable {
  private int num = 100;
  public static int staticNum = 100;
  boolean useStaticMethod;

  public SynchronizeMethod(boolean useStaticMethodToTest) {
    this.useStaticMethod = useStaticMethodToTest;
  }

  // 对于非静态方法,同步锁对象即this
  public synchronized void method() {
    System.out.println("Thread ID:" + Thread.currentThread().getId() + "---num:" + num);
    num--;
  }

  // 对于静态方法,同步锁对象是当前方法所在类的字节码对象
  public synchronized static void staticMethod() {
    System.out.println("Static Method Thread ID:" + Thread.currentThread().getId() + "---num:" + staticNum);
    staticNum--;
  }

  @Override
  public void run() {
    if (useStaticMethod) { // 测试静态同步方法
      while (staticNum > 1) {
        staticMethod();
      }
    }else{ // 测试非静态同步方法
      while (num > 1){
        method();
      }
    }
    System.out.println("Thread ID:" + Thread.currentThread().getId() + " exit");
  }
}

ReentrantLock测试类

package base.synchronize;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class SynchronizeLock implements Runnable {
  private Lock lock = null;
  private int num = 100;

  public SynchronizeLock(boolean fair){
    lock = new ReentrantLock(fair); // 可重入锁
  }

  @Override
  public void run() {
    while (num > 1) {
      try {
        lock.lock();
        System.out.println("Thread ID:" + Thread.currentThread().getId() + "---num:" + num);
        num--;
      } catch (Exception e) {
        e.printStackTrace();
      }finally {
        lock.unlock();
      }
    }
    System.out.println("Thread ID:" + Thread.currentThread().getId() + " exit");
  }
}

测试三种机制的Demo

package base.synchronize;

public class Demo {
  public static void main(String[] args) {
    synchronizeBlockTest();   // 同步代码块
    synchronizeMethodTest();  // 同步非静态方法
    synchronizeStaticMethodTest(); // 同步静态方法
    synchronizeLockTest();  // 可重入锁机制
  }

  public static void synchronizeBlockTest(){
    Runnable run = new SynchronizeBlock();
    for(int i = 0; i < 3; i++){
      new Thread(run).start();
    }
  }

  public static void synchronizeMethodTest(){
    Runnable run = new SynchronizeMethod(false);
    for(int i = 0; i < 3; i++){
      new Thread(run).start();
    }

  }
  public static void synchronizeStaticMethodTest() {
    Runnable run = new SynchronizeMethod(true);
    for(int i = 0; i < 3; i++){
      new Thread(run).start();
    }
  }


  public static void synchronizeLockTest(){
    Runnable run = new SynchronizeLock(false); // true:使用公平锁 false:使用非公平锁
    for(int i = 0; i < 3; i++){
      new Thread(run).start();
    }
  }
}

无论哪种机制,都得到预期的效果,打印100-0

看完这篇关于详解Java如何实现线程同步的文章,如果觉得文章内容写得不错的话,可以把它分享出去给更多人看到。

推荐阅读:
  1. 如何实现java线程同步
  2. 详解易语言线程同步

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

java 线程 ava

上一篇:PHP实现邮件自动发送

下一篇:win7 x64安装.net 4.0 HRESULT 0xc8000222

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》