软件编程
位置:首页>> 软件编程>> java编程>> Java实现线程同步方法及原理详解

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

作者:main(0)  发布时间:2021-07-29 21:28:13 

标签: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

来源:https://www.cnblogs.com/main404/p/13020726.html

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com