java 多线程同步_详解Java多线程编程中的线程同步方法

1、多线程的同步:

1.1、同步机制:在多线程中,可能有多个线程试图访问一个有限的资源,必须预防这种情况的发生。所以引入了同步机制:在线程使用一个资源时为其加锁,这样其他的线程便不能访问那个资源了,直到解锁后才可以访问。

1.2、共享成员变量的例子:成员变量与局部变量:

成员变量:

如果一个变量是成员变量,那么多个线程对同一个对象的成员变量进行操作,这多个线程是共享一个成员变量的。

局部变量:

如果一个变量是局部变量,那么多个线程对同一个对象进行操作,每个线程都会有一个该局部变量的拷贝。他们之间的局部变量互不影响。

下面举例说明:

实现了Runnable的线程类:

class MyThread3 implements Runnable{

//两个线程操作同一个对象,共享成员变量

//int i;

@Override

public void run() {

//两个线程操作同一个对象,各自保存局部变量的拷贝

int i = 0;

while(i<100){

System.out.println(i);

i++;

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

}

}

}

在main方法中用两个线程操作同一个对象:

public static void main(String[] args) {

MyThread3 myThread = new MyThread3();

//下面两个线程对同一个对象(Runnable的实现类对象)进行操作

Thread thread = new Thread(myThread);

Thread thread2 = new Thread(myThread);

//各自保存局部变量的拷贝,互不影响,输出200个数字

thread.start();

thread2.start();

}

这里如果把i变成成员变量,则输出100个数字。

1.3、共享资源导致的读取错误下面举个例子,两个线程共用一个Number对象,通过Number类的getNumber方法获取数据,读取数据并改写时,发现了重复读操作:

首先创建一个Number类:

class Number{

private int number = 10;

public String getNumber(int i){

if(number > 0){

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

number -= i;

return "取出"+i+"成功,剩余数量:"+number;

}

return "取出"+i+"失败,剩余数量:"+number;

}

}

线程类,在线程类中的私有属性包含了Number类的引用:

class MyThread4 extends Thread{

//两个线程操作同一个对象,共享成员变量

Number number;

public MyThread4(Number number){

this.number = number;

}

@Override

public void run() {

System.out.println(number.getNumber(8));

}

}

在main函数中创建两个线程类,包含了同一个Number类实例的引用:

public static void main(String[] args) {

Number number = new Number();

//两个线程操作同一个对象,共享对象number的成员变量number

MyThread4 myThread = new MyThread4(number);

MyThread4 myThread2 = new MyThread4(number);

myThread.start();

myThread2.start();

}

这样,当第一个线程读取Number中的number变量时先保存下来再休眠0.1秒,然后第二个线程再读取number变量并保存,此时两个线程保存了同样的数字,在修改时,也就导致修改了同一个数字两次。

2、同步机制的实现:

在多线程并发编程中Synchronized一直是元老级角色,很多人都会称呼它为重量级锁,但是随着Java SE1.6对Synchronized进行了各种优化之后,有些情况下它并不那么重了”

Java中的每一个对象都可以作为锁。

对于同步方法,锁是当前实例对象。

对于静态同步方法,锁是当前对象的Class对象。

对于同步方法块,锁是Synchonized括号里配置的对象。

当一个线程试图访问同步代码块时,它首先必须得到锁,退出或抛出异常时必须释放锁。

2.1、使用synchronized关键字创建synchronized方法:使用synchronized关键字,该关键字修饰的方法叫做同步方法。

Java中每个对象都有一个锁或者称为监视器,当访问某个对象的synchronized方法时,表示将该对象上锁,而不仅仅是为该方法上锁。

这样如果一个对象的synchronized方法被某个线程执行时,其他线程无法访问该对象的任何synchronized方法(但是可以调用其他非synchronized的方法)。直至该synchronized方法执行完。

静态的synchronized方法调用情况:

当调用一个对象的静态synchronized方法时,它锁定的并不是synchronized方法所在的对象,而是synchronized方法所在对象对应的Class对象。这样,其他线程就不能调用该类的其他静态synchronized方法了,但是可以调用非静态的synchronized方法。

结论:执行静态synchronized方法锁方法所在对象,执行非静态synchronized方法锁方法所在对象对应的Class对象。

下面是多线程调用静态的方法的例子,由于锁定了方法所在对象对应的Class对象,其他线程无法调用该方法所在对象其他的静态synchronized方法:

/**

* 定义一个类,包含了线程类需要调用的方法

*/

class Compute1{

//这时如果某个线程调用该方法,

//将锁定synchronized方法所在对象对应的class对象,

//而不是锁定synchronized方法所在对象

public synchronized static void execute(){

for(int i = 0; i<100; i++){

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("compute1:execute1 " + i++);

}

}

public synchronized static void execute2(){

for(int i = 0; i<100; i++){

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("compute1:execute2 " + i++);

}

}

}

main方法中两个线程分别调用同一个对象的两个static synchronized方法:

public static void main(String[] args) {

Compute1 com = new Compute1();

Thread thread1 = new Thread1(com);

Thread thread2 = new Thread2(com);

thread1.start();

thread2.start();

}

一次只能调用一个静态方法,直到执行完成。

2.2、使用synchronized创建同步代码块:通过使用synchronized同步代码块,锁定一个对象,该对象作为可执行的标志从而达到同步的效果:

/**

* 定义一个类,包含了线程类需要调用的方法

*/

class Compute1{

//通过同步代码块锁定object1对象进行锁定了其他同样的synchronized代码块

private Object object1 = new Object();

public void execute(){

synchronized(object1){

for(int i = 0; i<100; i++){

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("compute1:execute1 " + i++);

}

}

}

public synchronized void execute2(){

synchronized(object1){

for(int i = 0; i<100; i++){

try {

Thread.sleep(100);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println("compute1:execute2 " + i++);

}

}

}

}

如果想要使用synchronized同步代码块达到和使用synchronized方法同样的效果,可以锁定this引用:

synchronized(this){

}

2.3、synchronized方法和synchronized同步代码块的区别:synchronized同步代码块只是锁定了该代码块,代码块外面的代码还是可以被访问的。

synchronized方法是粗粒度的并发控制,某一个时刻只能有一个线程执行该synchronized方法。

synchronized同步代码块是细粒度的并发控制,只会将块中的代码同步,代码块之外的代码可以被其他线程同时访问。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/563058.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java商品管理系统_【Java Web】简易商品信息管理系统——首个Web项目

正文之前在学习了一段时间的Java Web的内容之后&#xff0c;当然需要有个项目来练练手&#xff0c;我相信大多数人的首选项目都是信息管理系统吧&#xff0c;所以我选择了商品信息管理系统目前项目源码已全部上传至GitHub&#xff0c;欢迎大家来fork —— 商品信息管理系统正文…

java 向上舍入_介绍Java的大数类(BigDecimal)和八种舍入模式

1.BigDecimal简介BigDecimal 由任意精度的整数非标度值 和32 位的整数标度 (scale) 组成。如果为零或正数&#xff0c;则标度是小数点后的位数。如果为负数&#xff0c;则将该数的非标度值乘以 10 的负scale 次幂。因此&#xff0c;BigDecimal表示的数值是(unscaledValue 10-s…

java循环的内部改变循环变量的值_java在for循环中怎样修改参数值?

// 待认证QueryFilter queryFilter0 new QueryFilter();queryFilter0.addCommand(new Command("busStatus", Op.EQ, "0"));int taxStatus0 taxInfoDao.getCount(queryFilter0);int businessStatus0 businessInfoDao.getCount(queryFilter0);int socialS…

java redis rpush_Redis Rpush 命令

Redis Rpush 命令Redis Rpush 命令用于将一个或多个值插入到列表的尾部(最右边)。如果列表不存在&#xff0c;一个空列表会被创建并执行 RPUSH 操作。当列表存在但不是列表类型时&#xff0c;返回一个错误。注意&#xff1a;在 Redis 2.4 版本以前的 RPUSH 命令&#xff0c;都只…

java jstat 命令_java高分局之jstat命令使用(转)

转自:http://blog.csdn.net/h_025/article/details/52813817java高分局之jstat命令使用jstat命令可以查看堆内存各部分的使用量&#xff0c;以及加载类的数量。命令的格式如下&#xff1a;jstat [-命令选项] [vmid] [间隔时间/毫秒] [查询次数]注意&#xff1a;使用的jdk版本是…

java判_java中判空

一、概述java中判等似乎很简单&#xff0c;用来判断对象引用(内存地址)是否相同&#xff0c;equals用来判断值是否相同。你可以试用String对象轻松区分这一点。那么在null判等(也就是判空操作)时呢&#xff1f;可以通过如下代码明白两个判等的比较&#xff1a;String name nul…

java启动应用_java 学习:在java中启动其他应用,由jenkins想到的

在jenkins的实践中遇到了一个问题&#xff1a;我的项目依赖其他第三方应用的地方比较多&#xff0c;而且会占用多个端口&#xff0c;如何处理端口和启动/关闭第三方应用成了难题。初级解决方案&#xff1a;在服务端上面写一堆bat文件&#xff0c;&#xff0c;&#xff0c;&…

java逻辑编程题_用Java编程解决一道逻辑推理题

package mytest;import java.util.Scanner;public class Test14 {/*** 竞赛结果表明&#xff0c;他们都说对了一半&#xff0c;说错了一半&#xff0c;并且无并列名次&#xff0c;试编程输出a,b,c,d的各个名次。* 分析&#xff1a;* 我们将老师的预测列成二维数组形式。行数是老…

python3线程池爬虫_python3爬虫中多线程的优势总结

有些小伙伴跟小编讨论了python中使用多线程原理的问题&#xff0c;就聊到了关于python多线程的弊端问题&#xff0c;这点可能在使用的过程中大家会能感觉到。而且之前讲过的GIL也是对python多线程的一种限制。那么&#xff0c;我们为什么还要用多线程呢&#xff1f;当然是多线程…

java表格的创建_Java创建表格实例详解 原创

表格是最常用的数据统计形式之一&#xff0c;在 swing 中 由 JTable 类实现表格。接下来&#xff0c;我们看看怎么利用 JTable 创建表格。在 JTable 类中除了默认的构造方法外&#xff0c;还提供了利用指定表格列名数组和表格数据数组创建表格的构造方法&#xff0c;代码如下&a…

java insert方法_【Oracle/Java】以Insert ALL方式向表中插入百万条记录,耗时9分17秒...

packagecom.hy;importjava.sql.Connection;importjava.sql.DriverManager;importjava.sql.ResultSet;importjava.sql.SQLException;importjava.sql.Statement;importjava.text.MessageFormat;/*** 百万数据插入Oracle表中*authorhorn1**/public classMillionInserter {//连接到…

nodejs mac java home_Mac上搭建nodejs开发环境

###Mac上搭建nodejs开发环境####安装homebrew123ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"brew updatebrew doctor####安装nodejs通过brew安装nodejs和grunt12brew install nodenpm install -g grunt-cli安装成功…

java spring mvc_java spring mvc 全注解

本人苦逼学生一枚,马上就要毕业,面临找工作,实在是不想离开学校.在老师的教导下学习了spring mvc ,配置文件实在繁琐,因此网上百度学习了spring mvc 全注解方式完成spring的装配工作;废话不多说了上干货,其实我也没怎么理解不过简单的运行了一个spring mvc 全注解项目,也不能说…

java note项目_Java Request.setNote方法代码示例

import org.apache.catalina.connector.Request; //导入方法依赖的package包/类/*** Perform single-sign-on support processing for this request.** param request The servlet request we are processing* param response The servlet response we are creating** exceptio…

java 检索编号输出信息_java,_java 如何解析txt文档,输入检索信息,然后输出,java - phpStudy...

java 如何解析txt文档&#xff0c;输入检索信息&#xff0c;然后输出请输入代码需求&#xff1a;请解析config.txt&#xff0c;文件格式包括段落名称、字段名称和字段值。段落名称的值为&#xff1a;"segment:"右边的字符串&#xff0c;在一个文件中不会有重复的段落…

java语言有没有平台无关性_Java语言具有良好的安全性和可移植性及平台无关性。...

【判断题】在类的定义中如果不明确给出父类,那么默认父类是Object类。【判断题】数组一旦创建大小不可改变。【单选题】手绘天花布置图的表示方法中,凡是剖到的墙、柱的断面轮廓线用( )绘制。【单选题】天花表面有进退关系的处理形式,常常采用暗灯槽,以及与各种类型的吊灯、吸顶…

java 配置hdfs集群_Hadoop集群搭建-04安装配置HDFS

HDFS是配合Hadoop使用的分布式文件系统&#xff0c;分为namenode: nn1.hadoop nn2.hadoopdatanode: s1.hadoop s2.hadoop s3.hadoop(看不明白这5台虚拟机的请看前面 01前期准备 )解压配置文件[hadoopnn1 hadoop_base_op]$ ./ssh_all.sh mv /usr/local/hadoop/etc/hadoop /usr/l…

使用双异步后,从 191s 优化到 2s

目录 一、一般我会这样做&#xff1a;操作起来&#xff0c;如果文件比较多&#xff0c;数据量都很大的时候&#xff0c;会非常慢。 二、谁写的&#xff1f;拖出去&#xff0c;斩了&#xff01;优化1&#xff1a;先查询全部数据&#xff0c;缓存到map中&#xff0c;插入前再进行…

java xxe漏洞利用_【技术分享】XXE漏洞攻防之我见

作者&#xff1a;激越王预估稿费&#xff1a;400RMB投稿方式&#xff1a;发送邮件至linwei#360.cn&#xff0c;或登陆网页版在线投稿你是否听说过xml注入攻击呢&#xff0c;或者对它只知其一不知其二呢&#xff1f;现在让我们从xml相关基础知识开始&#xff0c;一步步了解xml攻…

java ios压缩图片,Java、ios图片上传

IOS客服端代码interface ViewController (){NSString *boundary;NSString *fileParam;NSString *baseUrl;NSString *fileName;}endimplementation ViewController- (void)viewDidLoad{[super viewDidLoad];boundary "----------V2ymHFg03ehbqgZCaKO6jy";fileParam …