并行程序开发的一大关注重点就是线程安全,一般来说,程序并行化为了获取更多的执行效率,但前提是,高效率不能以牺牲正确性为代价,线程安全就是并行程序的根本和根基.volatile并不能真正保证线程安全,他只能确保一个线程修改了数据后,其他线程能够看到这个改动!
public class AccountingVol implements Runnable {
static AccountingVol instance = new AccountingVol();
static volatile int i = 0; public static void increase() {
i++;
} /**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see Thread#run()
*/
@Override
public void run() {
for (int j = 0; j < 10000000; j++) {
increase();
}
} public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start();t2.start();
t1.join();t2.join();
System.out.println("i = " + i);
}
}
上面代码显示了一个计数器,两个线程同时对i进行累加操作,各执行10000000次.我们希望得到的结果是20000000,但事实并非总是如此,得到的i总是小于预期结果!这就是线程不安全的恶果.
     为了解决这个问题Java提供了 synchronized来实现这个功能. 
  • synchronized的作用是实现线程间的同步问题,他的工作时对同步的代码加锁.使得每一次,只能有一个线程进入同步块,从而保证线程间的安全性,
关键字synchronized可以有很多用法,
  • 指定加锁对象:对给定加锁.进入同步代码前要获得给定对象的锁.
  • 直接作用于实例方法,相当于对当前实例加锁,进入同步代码前要获得当前实例的锁
  • 直接作用于静态方法,.相当于对当前类加锁,进入同步代码前要获得当前类的锁
我们队上边的例子修改,让他线程安全:
public class AccountingSync implements Runnable {
static AccountingSync instance = new AccountingSync();
static int i = 0; /**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see Thread#run()
*/
@Override
public void run() {
for (int j = 0; j < 10000000; j++) {
synchronized (instance) {
i++;
}
}
} public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start();t2.start();
t1.join();t2.join();
System.out.println("i = " + i);
}
} //上述代码还可以写成下面的形式:
public class AccountingSync2 implements Runnable {
static AccountingSync2 instance = new AccountingSync2();
static int i = 0; public synchronized void increase() {
i++;
} @Override
public void run() {
for (int j = 0; j < 10000000; j++) {
increase();
}
} public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(instance);
Thread t2 = new Thread(instance);
t1.start();t2.start();
t1.join();t2.join();
System.out.println("i = " + i);
}
} //一种错误的同步方式如下:
public class AccountingSyncBad implements Runnable { static int i = 0; public synchronized void increase() {
i++;
} /**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see Thread#run()
*/
@Override
public void run() {
for (int j = 0; j < 10000000; j++) {
increase();
}
} public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new AccountingSyncBad());
Thread t2 = new Thread(new AccountingSyncBad());
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("i = " + i);
}
}
 
虽然我们对increase()方法 做了同步处理,但是2个线程指向的是不同的实例.换言之就是.两个线程使用的是两把不同的锁.因此无法保证线程安全
修改如下:
public static synchronized void increase() {
    i++;
}
 
这样increase()方式就是类方法,而不是实例方法,因此线程还是可以同步的.
 
     除了用于线程同步,确保线程安全之外,synchronized还可以确保线程间的可见性和有序性.从可见性角度上讲,synchronized可以完全替代volatile的功能,只是使用上没有那么方便,就有序性而言,由于synchronized限制每一次只能有一个线程可以访问同步快,.因此 无论同步块内代码如何被乱序执行,只要确保串行语义一致,那么执行结果总是一样的.而其他访问线程.又必须在获得锁后方能进入代码块读取数据,因此,它们看到的最终结果并不取决于代码的执行过程,从而有序性问题自然得到了解决,换言之,被synchronized限制了多个线程是串行执行的.

线程安全的概念和Synchronized(读书笔记)的更多相关文章

  1. 《实战Java高并发程序设计》读书笔记

    文章目录 第二章 Java并行程序基础 2.1 线程的基本操作 2.1.1 线程中断 2.1.2 等待(wait)和通知(notify) 2.1.3 等待线程结束(join)和谦让(yield) 2. ...

  2. 《深入了解java虚拟机》高效并发读书笔记——Java内存模型,线程,线程安全 与锁优化

    <深入了解java虚拟机>高效并发读书笔记--Java内存模型,线程,线程安全 与锁优化 本文主要参考<深入了解java虚拟机>高效并发章节 关于锁升级,偏向锁,轻量级锁参考& ...

  3. 《android开发艺术探索》读书笔记(十一)--Android的线程和线程池

    接上篇<android开发艺术探索>读书笔记(十)--Android的消息机制 No1: 在Android中可以扮演线程角色的有很多,比如AsyncTask.IntentService.H ...

  4. Java并发读书笔记:线程安全与互斥同步

    目录 导致线程不安全的原因 什么是线程安全 不可变 绝对线程安全 相对线程安全 线程兼容 线程对立 互斥同步实现线程安全 synchronized内置锁 锁即对象 是否要释放锁 实现原理 啥是重进入? ...

  5. 《Java并发编程实战》第二章 线程安全性 读书笔记

    一.什么是线程安全性 编写线程安全的代码 核心在于要对状态訪问操作进行管理. 共享,可变的状态的訪问 - 前者表示多个线程訪问, 后者声明周期内发生改变. 线程安全性 核心概念是正确性.某个类的行为与 ...

  6. windows线程池四种情形(win核心读书笔记)

    windows线程池四种情形(win核心读书笔记) Mircosoft从Windows2000引入线程池API,并在Vista后对线程池重新构架,引入新的线程池API.以下所有线程池函数均适用于Vis ...

  7. Java并发读书笔记:如何实现线程间正确通信

    目录 一.synchronized 与 volatile 二.等待/通知机制 等待 通知 面试常问的几个问题 sleep方法和wait方法的区别 关于放弃对象监视器 三.等待通知典型 生产者消费者模型 ...

  8. Java并发读书笔记:线程通信之等待通知机制

    目录 synchronized 与 volatile 等待/通知机制 等待 通知 面试常问的几个问题 sleep方法和wait方法的区别 关于放弃对象监视器 在并发编程中,保证线程同步,从而实现线程之 ...

  9. Java Concurrency in Practice 读书笔记 第十章

    粗略看完<Java Concurrency in Practice>这部书,确实是多线程/并发编程的一本好书.里面对各种并发的技术解释得比较透彻,虽然是面向Java的,但很多概念在其他语言 ...

随机推荐

  1. C#从大图中截取一部分图片

    #region 从大图中截取一部分图片 /// <summary> /// 从大图中截取一部分图片 /// </summary> /// <param name=&quo ...

  2. 【转】Unity3D学习日记(二)使用UGUI制作虚拟摇杆控制摄像机

    http://blog.csdn.net/begonia__z/article/details/51178907 前天撸了一个简单的UGUI虚拟摇杆,今天我就利用前天做的虚拟摇杆做了一个简单的摄像机控 ...

  3. Java的代码转C#

    推荐个网站:点击打开链接 细节上有些小问题

  4. Codeforces Round #364 (Div. 2) A 水

    A. Cards time limit per test 1 second memory limit per test 256 megabytes input standard input outpu ...

  5. Mysql 数据库备份工具 xtrabackup

    1.安装测试数据库mysql5.7 详细步骤 yum install -y gcc gcc-c++ cmake bison ncurses-devel .tar.gz cd mysql-/ cmake ...

  6. StringBuilder与StringBuffer

    转:http://www.cnblogs.com/pepcod/archive/2013/02/16/2913557.html JAVA中用于处理字符串常用的有三个类: java.lang.Strin ...

  7. 部署私有Docker Registry

    安装部署一个私有的Docker Registry是引入.学习和使用Docker这门技术的必经之路之一.尤其是当Docker被所在组织接受,更多人.项目和产品开始接触和使用Docker时,存储和分发自制 ...

  8. [AGC008F] Black Radius(树形dp)

    神题啊!! Description 给你一棵有N个节点的树,节点编号为1到N,所有边的长度都为1 "全"对某些节点情有独钟,这些他喜欢的节点的信息会以一个长度为N的字符串s的形式给 ...

  9. 【HDOJ5532】Almost Sorted Array(签到)

    题意:给定一个n个数的数列,问删掉一个数之后剩余部分是否可以单调不增或单调不减 n<=1e5,a[i]<=1e5 思路:预处理一下前后缀是否合法 #include<cstdio> ...

  10. day5感想

    ---恢复内容开始--- 我感觉自己真的是太弱了,和那些从初中开始学的人TT 今天讲的数学,毕竟以前尖子生培训打过点基础,感觉还不错,但也仅限于听懂而已,打代码什么的…… 今天的内容: 一.数论 1. ...