文档章节

Java并发编程--从一个线程不安全的例子说起

Gaischen
 Gaischen
发布于 2012/10/27 22:28
字数 977
阅读 4324
收藏 14

并发问题再也不是一个只有高级程序员才能接触的问题了,在使用多线程编程的时候,我们更多的将目光放在追求系统的高并发和高吞吐,而这一切的前提是确保程序的正确性。在多线程编程中容易产生的问题有很多,比如线程安全问题、死锁、饥饿等。下面的例子将从线程安全开始,逐步开启并发编程的大门。

@NotThreadSafe
public class UnsafeSequence {
    private int value;

    /** Returns a unique value. */
    public int getNext() {
        return value++;
    }
}

这个例子来源于《Java Concurrency In Practice》的第一章,一个最最简单,却容易引起线程安全问题的片段。书中给出了如下解释:The problem with UnsafeSequence is that with some unlucky timing, two threads could call getNext and receive the same value. Figure 1.1 shows how this can happen. The increment notation, nextValue++, may appear to be a single operation, but is in fact three separate operations: read the value, add one to it, and write out the new value. Since operations in multiple threads may be arbitrarily interleaved by the runtime, it is possible for two threads to read the value at the same time, both see the same value, and then both add one to it. The result is that the same sequence number is returned from multiple calls in different threads.

Figure 1.1的确很明了的告诉我们线程推进的过程,这也给了我们一个寻找线程不安全的方法,通过这样图示法来分析问题。

当然,这里引出了第一个可能会引起线程不安全的因素:程序中有变量的读取、写入或判断操作

/**例如上述变量的自增*/
    public int getNext() {
        return value++;
    }
/**例如单例模式中队变量的判断操作*/
   Public Object getInstance(){
     If(obj==null){
  return new Object();
}
return obj;
}

写一个简单的程序验证一下上述问题,其实线程的学习最好的办法就是举例证明线程的不安全性,然后再想出解决方案,当然这也可能是这部分学习最难所在:

package com.a2.concurrency.chapter1;
/**
 * 线程安全第一种因素:程序中有变量的读取、写入或判断操作
 * @author ChenHui
 *
 */
public class UnsafeSequence {

	private int value;

	public int getValue() {
		return value++;
	}

	public static void main(String[] args) throws InterruptedException {
		
		final UnsafeSequence us = new UnsafeSequence();
		Thread th1 = new Thread("th1") {
			@Override
			public void run() {
				System.out.println( us.getValue()+" "+super.getName());
			}
		};

		Thread th2 = new Thread("th2") {
			@Override
			public void run() {
				System.out.println(us.getValue()+" "+super.getName());
			}
		};

		th1.start();
		/**
		 * 如果不執行Thread.sleep(1000);
		 * 偶尔結果为:
		 * 0 th2
		 * 0 th1
		 * 如果执行Thread.sleep(1000);
		 * 结果为:
		 * 0 th1
		 * 1 th2
		 */
		//Thread.sleep(1000);
		th2.start();
	}
}

对于这种因素产生的问题,我们先给出一种常用解决方案,就是使用同步机制。这里我们先给出最简单,大家也最容易想到的方案,对操作加synchronized关键字:

private volatile int value;
    public synchronized int getNext() {
        return value++;
    }

在这里使用了synchronized的情况下,是否使用volatile关键字并不是主要的。

这一节的最后例举一下一般会遇到线程安全问题的地方,引用自并发编程书中第一章:

Timer

Servlet/JSP

RMI

Swing

l  ……

注:synchronized 方法控制对类成员变量的访问: 每个类实例对应一把锁,每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行,否则所属 线程阻塞 ,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可 执行状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized 的成员函数中至多只有一个处于可执行状态(因为至多只有一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变量的方法均被声明为 synchronized)。


© 著作权归作者所有

Gaischen

Gaischen

粉丝 828
博文 55
码字总数 73789
作品 1
杭州
架构师
私信 提问
并发酷刑: 在 Java 内存模型中测试代码

不知道你是否这么觉得,而对于我来说最烦恼的bug就是处理并发问题。除非你已经掌握了利用其他工具摒弃你现有的工具. 但是,这里还有另外一个例子,因为我们已经在这里讲述了很多关于Java的知...

oschina
2014/03/12
1K
0
Java ThreadLocal 类的知识点解读

说起 Java 中的 ThreadLocal 类,可能很多安卓开发人员并不是很熟悉,毕竟很少有使用到的地方。但是如果你仔细分析过 Handler 源码的话,就一定见过这个类的出现。而 Handler 机制又是安卓知...

亦枫
2018/10/29
0
0
Java高并发--线程安全策略

Java高并发--线程安全策略 主要是学习慕课网实战视频《Java并发编程入门与高并发面试》的笔记 不可变对象 发布不可变对象可保证线程安全。 实现不可变对象有哪些要注意的地方?比如JDK中的S...

sunhaiyu
04/20
0
0
如何设计线程安全的Java程序

什么是线程安全的(thread-safe)? 在java中,线程安全的指的是代码可以在并发的或者多线程的环境下安全的使用或者共享,并且它们都将按照期望的方式运行。任何代码,类或者对象,如果它们在...

一条大河波浪宽
2013/10/04
904
0
读书笔记之《Java并发编程的艺术》-并发编程基础

读书笔记部分内容来源书出版书,版权归本书作者,如有错误,请指正。 欢迎star、fork,读书笔记系列会同步更新 git https://github.com/xuminwlt/j360-jdk module j360-jdk-thread/me.j360....

Hi徐敏
2015/11/11
4K
8

没有更多内容

加载失败,请刷新页面

加载更多

搭建高可用MongoDB集群(分片)

搭建高可用MongoDB集群(分片) MongoDB基础请参考:https://blog.51cto.com/kaliarch/2044423 MongoDB(replica set)请参考:https://blog.51cto.com/kaliarch/2044618 一、概述 1.1 背景 ......

linjin200
7分钟前
1
0
CDH6.0.1集成tez-0.9.1计算引擎

参考文章: https://www.jianshu.com/p/9fb9f32e1f0f https://www.baidu.com/link?url=OgpwasnZi7H1dySN2T111sseEWDBaCCTC3DFV61G7756YbrkJCA8Y3UFaueyqnfN&wd=&eqid=daeb8b3500049cf3000000......

Sheav
9分钟前
1
0
Vue内置指令的使用

v-model(数据绑定) v-model常用于表单数据的双向绑定,它本质上是一个语法糖。它主要的有两种应用: 在文本框、多行文本、input的下拉框、单选按钮、复选框中的应用 <div id="app"> ...

凌兮洛
10分钟前
1
0
外部来源应用检查-烦死了,终于找到解决设置了

Android 连接usb调试应用的时候: 华为关闭方法:1、设置-安全-更多安全设置,关掉外部来源应用检查。2、设置-系统-开发人员选项-关闭“监控ADB安装应用” 不知道OPPO 怎么关闭的?...

QGlaunch
11分钟前
2
0
6个K8s日志系统建设中的典型问题,你遇到过几个?

作者 | 元乙 阿里云日志服务数据采集客户端负责人,目前采集客户端 logtail 在集团百万规模部署,每天采集上万应用数 PB 数据,经历多次双 11、双 12 考验。 导读:随着 K8s 不断更新迭代,使...

阿里云官方博客
13分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部