线程安全问题

先看下面代码出现的问题:

定义一个Task类,里面有一个成员变量和一个有boolean类型参数的方法,方法内部会根据传入参数修改成员变量的值。

package com.sutaoyu.Thread;

public class Task {
//成员变量存储在堆内存里面,多个线程访问同一个堆内存,
//即多个线程可以同时修改num的值,这样会导致线程安全问题
private int num = 0;
public void changeNum(boolean flag) {
if(flag) {
num = 88;
System.out.println(Thread.currentThread().getName() + "======" + "begin");
System.out.println(Thread.currentThread().getName() + "=====" + num);
System.out.println(Thread.currentThread().getName() + "=====" + "over")
}else {
System.out.println(Thread.currentThread().getName() + "=====" + "begin");
System.out.println(Thread.currentThread().getName() + "=====" + num);
System.out.println(Thread.currentThread().getName() + "=====" + "over");
}
}
}

创建一个Task对象,将这个对象放到两个线程中,在这两个线程中分别调用changeNum方法

package com.sutaoyu.Thread;

public class SynchronizedTest01 {
public static void main(String[] args) {
Task task = new Task();
Thread t1 = new Thread() {
public void run() {
task.changeNum(true);
}
};
Thread t2 = new Thread() {
public void run(){
task.changeNum(false);
}
}; t1.start();
t2.start();
}
}

上面的代码有可能会出现打印这样的结果:

Thread-1=====begin
Thread-0=====begin
Thread-1=====66
Thread-0=====66
Thread-1=====over
Thread-0=====over

正常情况下应该打印出一个88一个66,可是上面却两个线程打印出的两个66,这样就出现了线程安全的问题,出现这个问题的原因是成员变量存储在堆内存中,两个线程共享堆内存,即两个线程可以对同一个num进行修改。
程序执行分析:
cpu执行t1线程,将num修改为88,之后cpu开始执行t2线程,将num修改为66,打印出66,cpu开始执行t1线程,打印num的值,此时num的值是66。

内存图解:

同步和异步

比如你要给A,B,C三人发消息
同步:先给A发,等A回复后,再给B发,等B回复后,再给C发,排队等待
异步:直接给A,B,C发消息,中间不需要等某人回复之后再给其他人发消息,不用排队等待

使用synchronized将方法设置为同步

将Task中的changeNum方法设置为同步的

public synchronized void changeNum(boolean flag)

在方法上加入synchronized关键字,这样在执行多个线程时看哪个线程先执行这个方法,假设有t1,t2,t3三个线程中都调用了changeNum方法,t1线程先执行了这个方法,那么t1会先在Task对象上面加锁,加锁后,别的线程就无法执行当前Task对象上的changeNum方法,直到t1执行结束changeNum方法之后,t2,t3中的一个线程才可以执行这个方法,这就保证了在某个时间段内只有一个线程执行changeNum方法,解决了线程安全问题。
注意:synchronized锁住的是当前对象,如果t1线程和t2线程里面是不同的对象,则不需要同步,因为不会发生线程安全问题。如下代码:

package com.sutaoyu.Thread;

public class SynchronizedTest01 {
public static void main(String[] args) { Task task1 = new Task();
Task task2 = new Task(); Thread t1 = new Thread() {
public void run() {
task1.changeNum(true);
}
};
Thread t2 = new Thread() {
public void run(){
task2.changeNum(false);
}
}; t1.start();
t2.start();
}
}

58、synchronized同步方法的更多相关文章

  1. synchronized同步方法《二》

    1.synchronized方法和锁对象 (1).验证线程锁的是对象 代码如下: 1.1创建一个MyObject类: package edu.ymm.about_thread4; public cla ...

  2. synchronized同步方法

    “非线程安全”其实会在多个线程对同一个对象中的实例变量进行并发访问的时候产生,产生的后果是脏读,也就是取到的数据是被更改过的.而“线程安全”就是以获得的实例变量的值是经过同步处理的,不会出现脏读的现象 ...

  3. 四、java多线程核心技术——synchronized同步方法与synchronized同步快

    一.synchronized同步方法 论:"线程安全"与"非线程安全"是多线程的经典问题.synchronized()方法就是解决非线程安全的. 1.方法内的变 ...

  4. java多线程(二)——锁机制synchronized(同步方法)

    synchronized Java语言的关键字,可用来给对象和方法或者代码块加锁,当它锁定一个方法或者一个代码块的时候,同一时刻最多只有一个线程执行这段代码.当两个并发线程访问同一个对象object中 ...

  5. 深入理解使用synchronized同步方法和同步代码块的区别

    一.代码块和方法之间的区别 首先需要知道代码块和方法有什么区别: 构造器和方法块,构造器可以重载也就是说明在创建对象时可以按照不同的构造器来创建,那么构造器是属于对象,而代码块呢他是给所有的对象初始化 ...

  6. synchronized同步方法《一》

    1.方法内的变量为线程安全 "非线程安全"问题存在于"实例变量"中,如果是方法内部的私有变量,则不存在"非线程安全"问题,所得结果也就是&q ...

  7. 二十二 synchronized同步方法

    一 Synchronized锁: 1 synchronized取得的锁都是对象锁,而不是把一段代码或方法加锁. synchronized是给该方法的实例对象加锁.如果多个线程访问的是同一个对象  的s ...

  8. synchronized同步方法和同步代码块的区别

    同步方法默认使用this或者当前类做为锁. 同步代码块可以选择以什么来加锁,比同步方法更精确,我们可以选择只有会在同步发生同步问题的代码加锁,而并不是整个方法. 同步方法使用synchronized修 ...

  9. java synchronized静态同步方法与非静态同步方法,同步语句块

    摘自:http://topmanopensource.iteye.com/blog/1738178 进行多线程编程,同步控制是非常重要的,而同步控制就涉及到了锁. 对代码进行同步控制我们可以选择同步方 ...

随机推荐

  1. .NET Core 中的并发编程

    今天我们购买的每台电脑都有一个多核心的 CPU,允许它并行执行多个指令.操作系统通过将进程调度到不同的内核来发挥这个结构的优点. 然而,还可以通过异步 I/O 操作和并行处理来帮助我们提高单个应用程序 ...

  2. ACM数论之旅17---反演定理 第一回 二项式反演(神说要有光 于是就有了光(´・ω・`))

    终于讲到反演定理了,反演定理这种东西记一下公式就好了,反正我是证明不出来的~(-o ̄▽ ̄)-o 首先,著名的反演公式 我先简单的写一下o( ̄ヘ ̄*o) 比如下面这个公式 f(n) = g(1) + g ...

  3. Java多线程(五) —— 线程并发库之锁机制

    参考文献: http://www.blogjava.net/xylz/archive/2010/07/08/325587.html 一.Lock与ReentrantLock 前面的章节主要谈谈原子操作 ...

  4. BZOJ 2143 飞飞侠(分层最短路)

    飞飞国是一个N×M的矩形方阵,每个格子代表一个街区.然而飞飞国是没有交通工具的.飞飞侠完全靠地面的弹射装置来移动.每个街区都装有弹射装置.使用弹射装置是需要支付一定费用的.而且每个弹射装置都有自己的弹 ...

  5. java.lang.IllegalArgumentException: Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986

    微信小程序前后台使用get方式传参时报错如图.但在微信开发平台和苹果测试都没事,在安卓手机上就报这个错,猜想原因是get传递了汉字的原因. 尝试了下在后台输出从前台获取的参数,但是后台什么也没有获取到 ...

  6. word2010激活工具使用方法

    1.关闭杀毒,关闭正打开着的word文档 2.执行Activator_v1.2.exe-->Activation Office 2010VL -->按1 -->完毕. 3.打开wor ...

  7. 【BZOJ4709】【Jsoi2011】柠檬

    Description 传送门 题意简述:将序列划分成任意多段,从每一段选出一个数\(x\),获得\(在这一段出现的次数x*(x在这一段出现的次数)\)的贡献.求总贡献最大值. Solution ​ ...

  8. BZOJ2529 [Poi2011]Sticks 【贪心】

    题目链接 BZOJ2529 题解 要组成三角形,当且仅当最长边长度小于另两条边之和 我们就枚举最长边,另两条边当然是越大越好 我们将所有边排序,从小枚举并记录各个颜色的最长边 当枚举到当前边时,找到除 ...

  9. 洛谷 P1356 数列的整数性 解题报告

    P1356 数列的整数性 题目描述 对于任意一个整数数列,我们可以在每两个整数中间任意放一个符号'+'或'-',这样就可以构成一个表达式,也就可以计算出表达式的值.比如,现在有一个整数数列:17,5, ...

  10. 【bzoj2301】 HAOI2011—Problem b

    http://www.lydsy.com/JudgeOnline/problem.php?id=2301 (题目链接) 题意 给出${a,b,c,d,k}$,${n}$组询问,求$${\sum_{i= ...