当前位置: 首页 > 编程日记 > 正文

(转)线程的同步

Java线程:线程的同步-同步方法
线程的同步是保证多线程安全访问竞争资源的一种手段。
线程的同步是Java多线程编程的难点,往往开发者搞不清楚什么是竞争资源、什么时候需要考虑同步,怎么同步等等问题,当然,这些问题没有很明确的答案,但有些原则问题需要考虑,是否有竞争资源被同时改动的问题?
在本文之前,请参阅《Java线程:线程的同步与锁》,本文是在此基础上所写的。
对于同步,在具体的Java代码中需要完成一下两个操作:
把竞争访问的资源标识为private;
同步哪些修改变量的代码,使用synchronized关键字同步方法或代码。
当然这不是唯一控制并发安全的途径。
synchronized关键字使用说明
synchronized只能标记非抽象的方法,不能标识成员变量。
为了演示同步方法的使用,构建了一个信用卡账户,起初信用额为100w,然后模拟透支、存款等多个操作。显然银行账户User对象是个竞争资源,而多个并发操作的是账户方法oper(int x),当然应该在此方法上加上同步,并将账户的余额设为私有变量,禁止直接访问。
/** 
* Java线程:线程的同步 

* @author leizhimin 2009-11-4 11:23:32 
*/
 
public class Test { 
        public static void main(String[] args) { 
                User u = new User("张三", 100); 
                MyThread t1 = new MyThread("线程A", u, 20); 
                MyThread t2 = new MyThread("线程B", u, -60); 
                MyThread t3 = new MyThread("线程C", u, -80); 
                MyThread t4 = new MyThread("线程D", u, -30); 
                MyThread t5 = new MyThread("线程E", u, 32); 
                MyThread t6 = new MyThread("线程F", u, 21); 

                t1.start(); 
                t2.start(); 
                t3.start(); 
                t4.start(); 
                t5.start(); 
                t6.start(); 
        } 


class MyThread extends Thread { 
        private User u; 
        private int y = 0; 

        MyThread(String name, User u, int y) { 
                super(name); 
                this.u = u; 
                this.y = y; 
        } 

        public void run() { 
                u.oper(y); 
        } 


class User { 
        private String code; 
        private int cash; 

        User(String code, int cash) { 
                this.code = code; 
                this.cash = cash; 
        } 

        public String getCode() { 
                return code; 
        } 

        public void setCode(String code) { 
                this.code = code; 
        } 

        /** 
         * 业务方法 
         * @param x 添加x万元 
         */
 
        public synchronized void oper(int x) { 
                try { 
                        Thread.sleep(10L); 
                        this.cash += x; 
                        System.out.println(Thread.currentThread().getName() + "运行结束,增加“" + x + "”,当前用户账户余额为:" + cash); 
                        Thread.sleep(10L); 
                } catch (InterruptedException e) { 
                        e.printStackTrace(); 
                } 
        } 

        @Override 
        public String toString() { 
                return "User{" + 
                                "code='" + code + '\'' + 
                                ", cash=" + cash + 
                                '}'; 
        } 
}
输出结果:
线程A运行结束,增加“20”,当前用户账户余额为:120 
线程F运行结束,增加“21”,当前用户账户余额为:141 
线程E运行结束,增加“32”,当前用户账户余额为:173 
线程C运行结束,增加“-80”,当前用户账户余额为:93 
线程B运行结束,增加“-60”,当前用户账户余额为:33 
线程D运行结束,增加“-30”,当前用户账户余额为:3 

Process finished with exit code 0
反面教材,不同步的情况,也就是去掉oper(int x)方法的synchronized修饰符,然后运行程序,结果如下:
线程A运行结束,增加“20”,当前用户账户余额为:61 
线程D运行结束,增加“-30”,当前用户账户余额为:63 
线程B运行结束,增加“-60”,当前用户账户余额为:3 
线程F运行结束,增加“21”,当前用户账户余额为:61 
线程E运行结束,增加“32”,当前用户账户余额为:93 
线程C运行结束,增加“-80”,当前用户账户余额为:61 

Process finished with exit code 0
很显然,上面的结果是错误的,导致错误的原因是多个线程并发访问了竞争资源u,并对u的属性做了改动。
可见同步的重要性。
注意:
通过前文可知,线程退出同步方法时将释放掉方法所属对象的锁,但还应该注意的是,同步方法中还可以使用特定的方法对线程进行调度。这些方法来自于java.lang.Object类。
void notify()    
                    唤醒在此对象监视器上等待的单个线程。    
void notifyAll()    
                    唤醒在此对象监视器上等待的所有线程。    
void wait()    
                    导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。    
void wait(long timeout)    
                    导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量。    
void wait(long timeout, int nanos)    
                    导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量。
结合以上方法,处理多线程同步与互斥问题非常重要,著名的生产者-消费者例子就是一个经典的例子,任何语言多线程必学的例子。


Java线程:线程的同步-同步块
对于同步,除了同步方法外,还可以使用同步代码块,有时候同步代码块会带来比同步方法更好的效果。
追其同步的根本的目的,是控制竞争资源的正确的访问,因此只要在访问竞争资源的时候保证同一时刻只能一个线程访问即可,因此Java引入了同步代码快的策略,以提高性能。
在上个例子的基础上,对oper方法做了改动,由同步方法改为同步代码块模式,程序的执行逻辑并没有问题。
/** 
* Java线程:线程的同步-同步代码块 

* @author leizhimin 2009-11-4 11:23:32 
*/
 
public class Test { 
        public static void main(String[] args) { 
                User u = new User("张三", 100); 
                MyThread t1 = new MyThread("线程A", u, 20); 
                MyThread t2 = new MyThread("线程B", u, -60); 
                MyThread t3 = new MyThread("线程C", u, -80); 
                MyThread t4 = new MyThread("线程D", u, -30); 
                MyThread t5 = new MyThread("线程E", u, 32); 
                MyThread t6 = new MyThread("线程F", u, 21); 

                t1.start(); 
                t2.start(); 
                t3.start(); 
                t4.start(); 
                t5.start(); 
                t6.start(); 
        } 


class MyThread extends Thread { 
        private User u; 
        private int y = 0; 

        MyThread(String name, User u, int y) { 
                super(name); 
                this.u = u; 
                this.y = y; 
        } 

        public void run() { 
                u.oper(y); 
        } 


class User { 
        private String code; 
        private int cash; 

        User(String code, int cash) { 
                this.code = code; 
                this.cash = cash; 
        } 

        public String getCode() { 
                return code; 
        } 

        public void setCode(String code) { 
                this.code = code; 
        } 

        /** 
         * 业务方法 
         * 
         * @param x 添加x万元 
         */
 
        public void oper(int x) { 
                try { 
                        Thread.sleep(10L); 
                        synchronized (this) { 
                                this.cash += x; 
                                System.out.println(Thread.currentThread().getName() + "运行结束,增加“" + x + "”,当前用户账户余额为:" + cash); 
                        } 
                        Thread.sleep(10L); 
                } catch (InterruptedException e) { 
                        e.printStackTrace(); 
                } 
        } 

        @Override 
        public String toString() { 
                return "User{" + 
                                "code='" + code + '\'' + 
                                ", cash=" + cash + 
                                '}'; 
        } 
}
线程E运行结束,增加“32”,当前用户账户余额为:132 
线程B运行结束,增加“-60”,当前用户账户余额为:72 
线程D运行结束,增加“-30”,当前用户账户余额为:42 
线程F运行结束,增加“21”,当前用户账户余额为:63 
线程C运行结束,增加“-80”,当前用户账户余额为:-17 
线程A运行结束,增加“20”,当前用户账户余额为:3 

Process finished with exit code 0
注意:
在使用synchronized关键字时候,应该尽可能避免在synchronized方法或synchronized块中使用sleep或者yield方法,因为synchronized程序块占有着对象锁,你休息那么其他的线程只能一边等着你醒来执行完了才能执行。不但严重影响效率,也不合逻辑。
同样,在同步程序块内调用yeild方法让出CPU资源也没有意义,因为你占用着锁,其他互斥线程还是无法访问同步程序块。当然与同步程序块无关的线程可以获得更多的执行时间。

转载于:https://www.cnblogs.com/lixuwu/p/5676198.html

相关文章:

wpf浏览器应用程序发布后获取当前应用地址

AppDomain.CurrentDomain.ApplicationIdentity.CodeBase 获取作为URL的部署清单的位置 Eg:发布前地址为E:\PROJECTWORK\LandaV8\bin\Debug\xxxxx.xbap(xxxxx.xbap为部署站点下的文件),部署后获取的地址为http://192.168.1.1/xxx…

微信小程序获取用户手机号,后端php实现 (前后端完整代码附效果图)

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 如图: 小程序代码: 第一步,登录,获取用户的 session_key; 第二步,点击按钮调用 bindgetphonenumber 事件,通过该事件…

pytorch与keras_Keras vs PyTorch:如何通过迁移学习区分外星人与掠食者

pytorch与kerasby Patryk Miziuła通过PatrykMiziuła Keras vs PyTorch:如何通过迁移学习区分外星人与掠食者 (Keras vs PyTorch: how to distinguish Aliens vs Predators with transfer learning) This article was written by Piotr Migdał, Rafał Jakubanis…

Ubuntu 16.04安装QQ(不一定成功)

注意1:如果是刚新装的系统,可以正常安装,但是,如果你已经装了很多软件,千万不要安装,因为会把系统上一般的依赖包和你之前装的软件全部卸载掉!甚至将桌面Dock都会卸载!最终只能重装U…

for循环动态的给select标签添加option内容

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 html <select class"form-control selectpicker" name"college" id"eq_num" data-actions-box"true" data-live-search"true" data-live-sea…

Linux下Debug模式启动Tomcat进行远程调试

J2EE开发各类资源下载清单, 史上最全IT资源&#xff0c;点击进入&#xff01; 一&#xff0e; 应用场景 在实际的测试过程中&#xff0c;可能会遇到由于程序执行的不间断性&#xff0c;我们无法构造测试场景来验证某个功能的正确性&#xff0c;只有通过代码级的调试才能验…

guice google_与Google Guice的动手实践

guice googleby Sankalp Bhatia通过Sankalp Bhatia 与Google Guice的动手实践 (A hands-on session with Google Guice) A few months ago, I wrote an article explaining dependency injection. I had mentioned of a follow-up article with a hands-on session of Google …

IQKeyboardManager使用方法

使用方法&#xff1a;将IQKeyboardManager 和 IQSegmentedNextPrevious类文件加进项目中。在AppDelegate文件中写下以下一行代码&#xff1a; [IQKeyBoardManager installKeyboardManager]; 搞定&#xff01; 也可以开启或者关闭keyboard avoiding功能&#xff1a; [IQKeyBoard…

JQ加AJAX 加PHP实现网页登录功能

微信小程序开发交流qq群 173683895 承接微信小程序开发。扫码加微信。 前端代码 <!DOCTYPE HTML> <html><head><link href"css/style.css" rel"stylesheet" type"text/css" media"all" /><meta http-eq…

web安全简介_Web安全:HTTP简介

web安全简介by Alex Nadalin通过亚历克斯纳达林 Web安全&#xff1a;HTTP简介 (Web Security: an introduction to HTTP) This is part 2 of a series on web security: part 1 was “Understanding The Browser”这是有关网络安全的系列文章的第2部分&#xff1a;第1部分是“…

继承实现的原理、子类中调用父类的方法、封装

一、继承实现的原来 1、继承顺序 Python的类可以继承多个类。继承多个类的时候&#xff0c;其属性的寻找的方法有两种&#xff0c;分别是深度优先和广度优先。 如下的结构&#xff0c;新式类和经典类的属性查找顺序都一致。顺序为D--->A--->E--->B--->C。 class E:…

hdu 5366 简单递推

记f[i]为在长度是i的格子上面至少放一个木桩的方法数。考虑第i个格子&#xff0c;有放和不放两种情况。 1.如果第i个格子放了一个木桩&#xff0c;则i - 1和i - 2格子上面不能放木桩&#xff0c;方案数为&#xff1a;f[i - 3] 1 2.如果第i个格子没有放木桩&#xff0c;则方案数…

git 代理 git_如何不再害怕GIT

git 代理 git了解减少不确定性的机制 (Understanding the machinery to whittle away the uncertainty) 到底什么是Git&#xff1f; (What is Git anyway?) “It’s a version control system.”“这是一个版本控制系统。” 我为什么需要它&#xff1f; (Why do I need it?)…

Python 基础 - Day 2 Assignment - ShoppingCart 购物车程序

作业要求 1、启动程序后&#xff0c;输入用户名密码后&#xff0c;如果是第一次登录&#xff0c;让用户输入工资&#xff0c;然后打印商品列表 2、允许用户根据商品编号购买商品 3、用户选择商品后&#xff0c;检测余额是否够&#xff0c;够就直接扣款&#xff0c;不够就提醒 4…

hdu 1878 欧拉回路

欧拉回路 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 10548 Accepted Submission(s): 3849 Problem Description欧拉回路是指不令笔离开纸面&#xff0c;可画过图中每条边仅一次&#xff0c;且可以回到起点…

bootstrap 时间日期日历控件(datetimepicker)附效果图

开发交流QQ群: 173683895 173683895 526474645 人满的请加其它群 效果图 代码 <!DOCTYPE html> <html><head><meta charset"UTF-8"><link href"https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel&q…

如何在您HTML中嵌入视频和音频

by Abhishek Jakhar通过阿比舍克贾卡(Abhishek Jakhar) 如何在您HTML中嵌入视频和音频 (How to embed video and audio in your HTML) HTML allows us to create standards-based video and audio players that don’t require the use of any plugins. Adding video and audi…

html 省份,城市 选择器附效果图

开发交流QQ群: 173683895 173683895 526474645 人满的请加其它群 效果图&#xff1a; 源码&#xff1a; <!DOCTYPE html> <html><head><meta charset"UTF-8"><link href"https://cdn.bootcss.com/bootstrap/3.3.7/css/boots…

机器学习:协方差矩阵

一、统计学的基本概念 统计学里最基本的概念就是样本的均值、方差、标准差。首先&#xff0c;我们给定一个含有n个样本的集合&#xff0c;下面给出这些概念的公式描述&#xff1a; 均值&#xff1a; 标准差&#xff1a; 方差&#xff1a; 均值描述的是样本集合的中间点&#xf…

TemplatedParent 与 TemplateBinding

http://blog.csdn.net/idebian/article/details/8761388转载于:https://www.cnblogs.com/changbaishan/p/4716414.html

避免成为垃圾邮件_如何避免犯垃圾

避免成为垃圾邮件by Yoel Zeldes由Yoel Zeldes 如何避免犯垃圾 (How to avoid committing junk) In the development process, every developer writes stuff they don’t intend to commit and push to the remote server, things like debug prints. It happens to all of u…

[bzoj2333] [SCOI2011]棘手的操作 (可并堆)

//以后为了凑字数还是把题面搬上来吧2333 发布时间果然各种应景。。。 Time Limit: 10 Sec Memory Limit: 128 MB Description 有N个节点&#xff0c;标号从1到N&#xff0c;这N个节点一开始相互不连通。第i个节点的初始权值为a[i]&#xff0c;接下来有如下一些操作&#xff1…

vue.js created函数注意事项

因为created钩子函数是页面一加载完就会调用的函数&#xff0c;所以如果你想在这个组件拿值或者是赋值&#xff0c;很可能this里面能拿到数据&#xff0c;但是如果你用this.赋值的话&#xff0c;控制台或者debugger都会发现this里面有你所想要的数据&#xff0c;但是赋值后就是…

JS删除城市的后缀

开发交流QQ群: 173683895 173683895 526474645 人满的请加其它群 代码 const deleteStr str >{if (str.indexOf("市") ! -1 || str.indexOf("州") ! -1){str str.substring(0, str.length - 1)console.log(删除城市的最后一个字,str)return s…

gatsby_将您的GraphCMS数据导入Gatsby

gatsbyLets set up Gatsby to pull data from GraphCMS.让我们设置Gatsby来从GraphCMS中提取数据。 This will be a walk-through of setting up some basic data on the headless CMS, GraphCMS and then querying that data in Gatsby.这将是在无头CMS&#xff0c;GraphCMS上…

Java学习笔记07--日期操作类

一、Date类 在java.util包中定义了Date类&#xff0c;Date类本身使用非常简单&#xff0c;直接输出其实例化对象即可。 public class T { public static void main(String[] args) { Date date new Date(); System.out.println("当前日期&#xff1a;"date); //当前…

javascript数组集锦

设计数组的函数方法 toString, toLocaleString, valueOf, concat, splice, slice indexOf,lastIndexOf, push, pop, shift, unshift, sort, reverse map, reduce, reduceRight, filter, every, some, forEach 创建数组 数组字面量创建&#xff1a;var arr [val1, val2, val3];…

JS实现HTML标签转义及反转义

开发交流QQ群: 173683895 173683895 526474645 人满的请加其它群 编码反编码 function html_encode(str) { var s ""; if (str.length 0) return ""; s str.replace(/&/g, "&amp;"); s s.replace(/</g, "<")…

喜欢把代码写一行的人_我最喜欢的代码行

喜欢把代码写一行的人Every developer has their favourite patterns, functions or bits of code. This is mine and I use it every day.每个开发人员都有自己喜欢的模式&#xff0c;功能或代码位。 这是我的&#xff0c;我每天都用。 它是什么&#xff1f; (What is it?) …

智能家居APP开发

智能家居APP开发 APP开发技术qq交流群&#xff1a;347072638 前言&#xff0c;随着智能硬件设备的流行&#xff0c;智能家居開始红火&#xff0c;智能家居就是家用电器的智能化。包含智能锁&#xff0c;灯&#xff0c;空调&#xff0c;灯&#xff0c;音箱等等&#xff0c;移动设…