线程安全问题

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

定义一个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. PHP开发网站,你是如何提高其网站的安全性的?

    一.网站程序问题 很多网站的安全问题大多是由于网站程序存在漏洞,所以想要提高网站安全性,必须要选择安全的后台cms系统,若有能力可以自己去开发网站后台,这样安全性能得到极大的提高,若是从网上选择一些免 ...

  2. Shopping Bands Rank & SBR

    Shopping Bands Rank SBR https://www.guiderank.org/index.html Nike Air Zoom Pegasus 34 http://www.shi ...

  3. Java并发编程实战2-线程安全

    1. 定义 一个类是线程安全的,是指在被多个线程访问时,类可以持续进行正确的行为. 2. WHY 我们想要的是线程安全的程序,为什么在线程安全的开始讲线程安全的类呢? 编写线程安全的代码,本质上就是管 ...

  4. MT【163】运动是相对的

    如图,在平面直角坐标系中,$P(6,8)$,四边形$ABCD$为矩形,$AB=16$,$AD=9$,点$A,B$分别在射线$OP$和$Ox$上,求$OD$的最大值_______            ...

  5. 【算法复习】codevs1022 匈牙利算法

    题目描述 Description 有一个N×M的单位方格中,其中有些方格是水塘,其他方格是陆地.如果要用1×2的矩阵区覆盖(覆盖过程不容许有任何部分重叠)这个陆地,那么最多可以覆盖多少陆地面积.   ...

  6. 【BZOJ2024】舞会(动态规划,容斥,高精度)

    [BZOJ2024]舞会(动态规划,容斥,高精度) 题面 BZOJ 洛谷 题解 这种关系显然要先排序才不会不想影响. 设\(f[i][j]\)表示前\(i\)个女生中,选了\(j\)个女生配对,并且女 ...

  7. 使用msiexec.exe绕过应用程序白名单(多种方法)

    0x00 前言 在我们之前的文章中,我们讨论了“Windows Applocker策略 - 初学者指南”,因为它们为应用程序控制策略定义了AppLocker规则,以及如何使用它们.但今天您将学习如何绕 ...

  8. bzoj 3772 :精神污染 线段树+打标记 or 主席树

    3772: 精神污染 Time Limit: 10 Sec  Memory Limit: 64 MBSubmit: 315  Solved: 87[Submit][Status][Discuss] D ...

  9. 【arc102E】Stop. Otherwise...

    Portal --> arc102E Description 有\(N\)个位置,每个位置可以填一个\(1\sim K\)的数,要求对于每一个\(i\in [2,2K]\),求出任意两个位置的和 ...

  10. MatConvNet+Matlab2017a+CUDA8.0安装

    安装过程参照MatConvNet官网给出的步骤: http://www.vlfeat.org/matconvnet/install/ 1.安装CUDA8.0+cudnn6.0 参见之前的博客 2.安装 ...