一、概述

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

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

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

java实现线程同步的方法_Java实现线程同步方法及原理详解相关推荐

  1. java mod 函数的使用方法_Java中 % 与Math.floorMod() 区别详解

    %为取余(rem),Math.floorMod()为取模(mod) 取余取模有什么区别呢? 对于整型数a,b来说,取模运算或者取余运算的方法都是: 1.求 整数商: c = a/b; 2.计算模或者余 ...

  2. java 线程同步的方法_Java多线程同步方法

    Java多线程同步方法 package com.wkcto.intrinsiclock; /** * synchronized同步实例方法 * 把整个方法体作为同步代码块 * 默认的锁对象是this对 ...

  3. java中math的方法_Java中Math类常用方法代码详解

    近期用到四舍五入想到以前整理了一点,就顺便重新整理好经常见到的一些四舍五入,后续遇到常用也会直接在这篇文章更新... public class Demo{ public static void mai ...

  4. java黄金分割数的解题思路_java 实现黄金分割数的示例详解

    黄金分割数 0.618 与美学有重要的关系.舞台上报幕员所站的位置大约就是舞台宽度的 0.618 处, 墙上的画像一般也挂在房间高度的 0.618 处,甚至股票的波动据说也能找到 0.618 的影子- ...

  5. java线程安全的方法_Java实现线程安全的方式

    多线程环境中如何保证线程安全?java可以实现线程安全的方式归纳如下: 1.使用synchronized关键字 synchronized关键字可以修饰方法和代码块,它的语义是保证同一段代码同一时间只能 ...

  6. java的循环控制结构有哪些_java中的控制结构(if,循环)详解

    1 说明JAVA语言中三种控制循环结构的代码形式(其他 1. while(condition){ statements; } 其中,condition是任何布尔表达式,其返回值为true 或 fals ...

  7. java 判断端口是否被占用_java检测端口是否被占用详解

    Java可以通过Socket类来检测端口是否被占用: import java.net.*; import java.io.*; public class Main { public static vo ...

  8. cordova监听事件中调用其他方法_Laravel模型事件的实现原理详解

    模型事件在 Laravel 的世界中,你对 Eloquent 大多数操作都会或多或少的触发一些模型事件,下面这篇文章主要给大家介绍了关于Laravel模型事件的实现原理,文中通过示例代码介绍的非常详细 ...

  9. Java中高级核心知识全面解析——常用框架(SpringMVC-工作原理详解)

    一.先来看一下什么是 MVC 模式 MVC 是一种设计模式. MVC 的原理图如下: 二.SpringMVC 简单介绍 SpringMVC 框架是以请求为驱动,围绕 Servlet 设计,将请求发给控 ...

最新文章

  1. js 变量、函数提升
  2. Kira同学:斩获百度校招提前批offer备战细节全揭秘
  3. Java Hashtable hashCode()方法及示例
  4. POJ 1380 坐标旋转
  5. 织梦留言板guestbook.htm加入头部导航
  6. Y2K Accounting Bug(poj2586)
  7. Introducing DataFrames in Apache Spark for Large Scale Data Science(中英双语)
  8. sklearn学习 6.聚类算法K-Means
  9. matches php,PHP 正则表达式 推荐
  10. Linux下安装Mysql详解
  11. Python基于共现提取《釜山行》人物关系
  12. c语言用函数写大小写转换,C语言实现大小写转换的三种方法
  13. 西游记中托塔李天王的三个儿子,一个女儿和一个干女儿
  14. 【产业互联网周报】容联云下周纽交所挂牌;声网Agora因Clubhouse股价周内涨超30%;贝索斯将卸任亚马逊CEO...
  15. 云​大数据和计算技术周报(第43期)
  16. 获取Shell命令执行错误结果
  17. 计算机内部线有,电脑主机内部有几根线?分别叫什么?
  18. 就决定是你啦!苏菲婆5! —— 谈谈我对Surface Pro 5的使用体验以及各种骚操作
  19. JavaScript -函数式编程
  20. 兰大计算机考试2020年5月在线考试答案,《计算机组成原理》兰大2020年9月在线考核试题题目及答案...

热门文章

  1. jni android 参数 字符串 jstring,2.4.5 jstring介绍
  2. QIIME 2教程. 14数据评估和质控q2-quality-control(2021.2)
  3. QIIME 2用户文档. 9数据导入Importing data(2019.7)
  4. Python使用matplotlib可视化分布点图、自定义设置分布点图的中位数数据点的颜色(Distributed Dot Plot)
  5. pandas使用query函数查询dataframe指定数据列的内容(数值)包含在特定列表中的数据行(select rows which column values contain in list)
  6. R语言使用scales包的hue_pal函数获取ggplot2任何级别的离散色码、使用scales包的hue_pal函数获取ggplot2任何级别的反序(reverse)离散色码
  7. R语言构建文本分类模型并使用LIME进行模型解释实战:文本数据预处理、构建词袋模型、构建xgboost文本分类模型、基于文本训练数据以及模型构建LIME解释器解释多个测试语料的预测结果并可视化
  8. R语言泊松分布函数Poisson Distribution(dpois, ppois, qpois rpois)实战
  9. python使用fpdf2包和pdfrw报包新内容添加到已有的PDF页面上
  10. Error in install.packages : cannot remove prior installation of package