您的位置:首页技术文章
文章详情页

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

【字号: 日期:2022-08-31 17:03:52浏览:3作者:猪猪

一、概述

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

例如:线程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
相关文章: