1.方法内的变量为线程安全

  "非线程安全"问题存在于"实例变量"中,如果是方法内部的私有变量,则不存在"非线程安全"问题,所得结果也就是"线程安全"了。下面我们来编写一个"线程安全"的例子:

1.1 HasSelfPrivate类如下:

package edu.ymm.about_thread;

public class HasSelfPrivate {
public void add1(String username) {
try {
int num = 0; //这就是方法类的变量
if(username.equals("a")) {
num = 100;
System.out.println("a set over");
Thread.sleep(2000); //用来等待b }else {
num = 200;
System.out.println("b set over");
}
System.out.println(username + "num = " + num);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

1.2  创建一个ThreadA类:

package edu.ymm.about_thread;

public class ThreadA extends Thread {

	private HasSelfPrivate numself;
public ThreadA(HasSelfPrivate numself) {
super();
this.numself = numself;
} @Override
public void run() {
super.run();
numself.add1("a ");
} }

1.3 创建一个ThreadB类:

package edu.ymm.about_thread;

public class ThreadB extends Thread {

	private HasSelfPrivate numself;
public ThreadB(HasSelfPrivate numself) {
super();
this.numself = numself;
}
@Override
public void run() {
super.run();
numself.add1("b ");
}
}

1.4 来测试一下这个例子:

package edu.ymm.about_thread;

public class Test {

	public static void main(String[] args) {

		HasSelfPrivate hPrivate = new HasSelfPrivate();
ThreadA threadA = new ThreadA(hPrivate);
threadA.start();
ThreadB threadB =new ThreadB(hPrivate);
threadB.start();
} }

执行结果如下:

可见,方法中的变量不存在非线程安全问题,永远是线程安全的。原因就是方法内部的变量是私有的。

2.实例变量非线程安全

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

  (2):用线程访问的对象中如果有多个实例变量,则运行的结果有可能出现交叉情况。

  (3):如果对象仅有1个实例变量,则可能出现覆盖的情况。

下面举一个例子:

2.1 HasSelfPrivate类如下:

package edu.ymm.about_thread1;

public class HasSelfPrivate {
private int num = 0;
public void add1(String username) {
try {
if(username.equals("a")) {
num = 100;
System.out.println("a set over");
Thread.sleep(3000); //用来等待b
}else {
num = 200;
System.out.println("b set over");
}
System.out.println(username + "num = " + num); } catch (InterruptedException e) {
e.printStackTrace();
}
}
}

2.2 创建一个ThreadA类:

package edu.ymm.about_thread1;

public class ThreadA extends Thread {

	private HasSelfPrivate numself;
public ThreadA(HasSelfPrivate numself) {
super();
this.numself = numself;
} @Override
public void run() {
super.run();
numself.add1("a ");
} }

2.3创建一个ThreadB类:

package edu.ymm.about_thread1;

public class ThreadB extends Thread {

	private HasSelfPrivate numself;
public ThreadB(HasSelfPrivate numself) {
super();
this.numself = numself;
}
@Override
public void run() {
super.run();
numself.add1("b ");
}
}

2.4来测试一下这个例子:

package edu.ymm.about_thread1;

public class Test {

	public static void main(String[] args) {

		HasSelfPrivate hPrivate = new HasSelfPrivate();
ThreadA threadA = new ThreadA(hPrivate);
threadA.start();
ThreadB threadB =new ThreadB(hPrivate);
threadB.start();
} }

结果如下:

  上述就是所谓的“非线程安全”的一个例子。a的值不是我们预期的100了。要解决这种现象,只需要在a和b共同访问的方法前加上“synchronized”就可以了。

更新这个类后:

package edu.ymm.about_thread1;

public class HasSelfPrivate {
private int num = 0;
synchronized public void add1(String username) {
try {
if(username.equals("a")) {
num = 100;
System.out.println("a set over");
Thread.sleep(2000); //用来等待b
}else {
num = 200;
System.out.println("b set over");
}
System.out.println(username + " num=" + num); } catch (InterruptedException e) {
e.printStackTrace();
}
}
}

再执行结果为:

所以,在两个线程访问同一个对象中的同步方法(synchronized)时一定是线程安全的。

3.多个对象多个锁

我们来改动一点:将测试中产生两个实例对象。

3.1 HasSelfPrivate类如下:

package edu.ymm.about_thread2;

public class HasSelfPrivate {
private int num = 0;
synchronized public void add1(String username) {
try {
if(username.equals("a")) {
num = 100;
System.out.println("a set over");
Thread.sleep(2000); //用来等待b
}else {
num = 200;
System.out.println("b set over");
}
System.out.println(username + " num=" + num); } catch (InterruptedException e) {
e.printStackTrace();
}
}
}

上面代码中有同步方方法add1,说明此方法应该被顺序调用。

3.2 创建一个ThreadA类:

package edu.ymm.about_thread2;

public class ThreadA extends Thread {

	private HasSelfPrivate numself;
public ThreadA(HasSelfPrivate numself) {
super();
this.numself = numself;
} @Override
public void run() {
super.run();
numself.add1("a");
} }

3.3创建一个ThreadB类:

package edu.ymm.about_thread2;

public class ThreadB extends Thread {

	private HasSelfPrivate numself;
public ThreadB(HasSelfPrivate numself) {
super();
this.numself = numself;
}
@Override
public void run() {
super.run();
numself.add1("b");
}
}

3.4来测试一下这个例子:

package edu.ymm.about_thread2;

public class Test {

	public static void main(String[] args) {

		HasSelfPrivate hPrivate1 = new HasSelfPrivate();
HasSelfPrivate hPrivate2 = new HasSelfPrivate();
ThreadA threadA = new ThreadA(hPrivate1);
threadA.start();
ThreadB threadB =new ThreadB(hPrivate2);
threadB.start();
} }

执行结果如下:

上述示例是两个线程分别访问一个类的两个不同实例的相同名称的同步方法,效果却是异步的方式运行的。本示例由于创建了2个业务对象,在系统中产生了两个锁,所以运行结果是异步的,打印的效果就是先打印b再打印a。

关键字synchronized取得的锁都是对象锁,而不是把一段代码或方法(函数)当作锁,所以在上面的示例中,哪个线程先执行带synchronized关键字的方法,哪个线程就持有该方法所属对象的锁Lock,那么其他线程只能呈等待状态,前提是多个线程访问的是同一个对象。

但是如果多个线程访问多个对象,则JVM会创建多个锁。

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同步方法

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

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

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

  8. 58、synchronized同步方法

    线程安全问题 先看下面代码出现的问题: 定义一个Task类,里面有一个成员变量和一个有boolean类型参数的方法,方法内部会根据传入参数修改成员变量的值. package com.sutaoyu.T ...

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

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

随机推荐

  1. Pycharm创建Django项目并访问Django

    Pycharm创建Django项目并访问Django 一.Django插件 如果没有Django插件,需要先安装Django插件. 1,首先点击Default Settings,打开设置页面: 2,打 ...

  2. 【题解】Luogu UVA12345 Dynamic len(set(a[L:R]))

    原题传送门 这题要用动态莫队,我博客里有介绍 这道题和luogu P1903 [国家集训队]数颜色 / 维护队列差不多,解法就在上面那篇博客里qaq 主要的问题是如何排序? 排序有三个关键字: 1.左 ...

  3. 导入maven项目各个注解均报错了

    所遇问题: 导入maven项目各个注解均报错了; 思考1: 这个项目使用了springboot;spring是个”大容器”,所有对象的创建和管理都交给了它, (SpringBoot是一个框架,一种全新 ...

  4. linux 压缩工具

    gzip gunzip zcat bzip2 bunzip2 bzcat xz unxz xzcat a:  gzip 用法 # gzip file  压缩文件 不会保留源文件 直接生成 file.g ...

  5. 2018年12月7日 字符串格式化2 format与函数1

    tp7="i am \033[44;1m %(name)-25.6s\033[0m"%{"name":"sxj2343333"} print ...

  6. rsync: read error: Connection reset by peer (104)

    Centos7    rsync守护进程上传文件失败 [root@nfs ~]# rsync -avz /etc rsync_backup@172.16.1.41::backupsending inc ...

  7. spring配置jax-ws

    在spring配置文件中新建bean(或者是在配置文件中添加bean),在该bean中添加指定的访问地址. @Bean public static SimpleJaxWsServiceExporter ...

  8. Spring 学习——Resources接口

    Resources 针对资源文件的统一接口 Resources UrlResource:URL对应的资源,只需要一个url即可构建 ClassPathResource:获取类路径下的资源文件 File ...

  9. Icons - Material Design各种ICON图标大全

    Icons - Material Design https://material.io/tools/icons/?icon=account_balance&style=baseline

  10. FJUT3565 最大公约数之和(容斥)题解

    题意:给n,m,求出 思路:题意为求出1~m所有数和n的gcd之和.显然gcd为n的因数.我们都知道gcd(a,b)= c,那么gcd(a/c,b/c)= 1.也就是说我们枚举n所有的因数k,然后去找 ...