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

网友投稿 300 2022-12-05


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类似

二、测试用例

同步代码块测试类

package base.synchronize;

publicxBObBmOdp 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.ReentrantLhttp://ock;

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


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Java实现简易生产者消费者模型过程解析
下一篇:Spring Boot 实现配置文件加解密原理
相关文章

 发表评论

暂时没有评论,来抢沙发吧~