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类似
二、测试用例
同步代码块测试类
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
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。