欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java实现线程同步方法及原理详解

程序员文章站 2022-05-20 18:53:40
一、概述无论是什么语言,在多线程编程中,常常会遇到多个线同时操作程某个变量(读/写),如果读/写不同步,则会造成不符合预期的结果。例如:线程a和线程b并发运行,都操作变量x,若线程a对变量x进行赋上一...

一、概述

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

例如:线程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

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。