线程同步

问题引入
观察一面一段小程序:
  1. public class Main {
  2. private static int amount = 0;
  3. public static void main(String[] args) {
  4. System.out.println(++amount);
  5. new MyThread("thread1").start();
  6. new MyThread("thread2").start();
  7. }
  8. private static void calc(String tag){
  9. ++amount;
  10. try {
  11. Thread.sleep(1);
  12. } catch (InterruptedException e) {
  13. e.printStackTrace();
  14. }
  15. System.out.println(tag + "==>" + amount);
  16. }
  17. static class MyThread extends Thread {
  18. private String name;
  19. public MyThread(String name) {
  20. super();
  21. this.name = name;
  22. }
  23. @Override
  24. public void run() {
  25. super.run();
  26. calc(name);
  27. }
  28. }
  29. }
运行结果:
上面的代码MyThread中先将amount累加1;再睡1S,打印数据。很显然thread1睡眠之后被打断,thread2被执行才会出现这样的情况。
系统对线程的调度是有一定随机性的。当多线程操作资源时,才会出现线程安全的问题。Java 提供了一系列的方案来解决这个问题,下面将一一说明。
Synchronized关键字
同步方法块
  1. synchronized(obj){
  2. ...
  3.        //此处是同步代码块
  4. }
当线程执行此段代码时必须持有锁,否则不能执行,上面代码修改如下所示即可恢复正常:
  1. //对象锁
  2. private static Object obj = new Object();
  3. private static void calc(String tag) {
  4. //执行此代码必须持有此锁,没有锁只能等待此锁的使用线程释放锁
  5. synchronized (obj) {
  6. ++amount;
  7. try {
  8. Thread.sleep(1);
  9. } catch (InterruptedException e) {
  10. e.printStackTrace();
  11. }
  12. System.out.println(tag + "==>" + amount);
  13. }
  14. }

同步方法
此关键字还可以直接修饰方法,被修饰的方法为同步方法。同步方法的使用也必须持有锁,此时锁定的是this(当前对象),
  1. private synchronized static void calc(String tag) {
  2. // 执行此代码必须持有此锁,没有锁只能等待此锁的使用线程释放锁
  3. ++amount;
  4. try {
  5. Thread.sleep(1);
  6. } catch (InterruptedException e) {
  7. e.printStackTrace();
  8. }
  9. System.out.println(tag + "==>" + amount);
  10. }
释放锁
   synchronized修饰的代码块或者同步方法没有显性的释放锁的方法。遇到以下几种情况会释放锁。
  • 使用synchronized关键字,必须等待当前线程执行完同步代码块或者同步方法,锁被释放。
  • 遇到return、break终止了当前代码块或者同步方法,锁被释放。
  • 遇到未处理的异常导致的崩溃,当前锁被释放。
  • 线程调用wait方法,释被放锁。
下面两点不会释放锁,需要注意:
  • 程序调用Thread.sleep()、Thread.yield(),当前线程不会释放锁。
  • 其他线程调用suspend方法,将此方法挂起,当前线程不会释放锁。同时应该避免使用suspend和resume方法控制线程。
访问权限总结
访问权限原则:当前线程持有某个锁时,其他线程无法访问被同一个锁锁定的方法或者代码块;与是否在一个类中,是否是静态无关,只与锁是否被释放有关。
常见的问题如下:
  • 一个类中,有多个方法,当前线程持有某锁,其他线程无法访问此锁锁定的其他同步方法,但是可以访问其他非同步方法
  • 一个类中有多个代码块或同步方法,当前线程持有某所,其他线程可以访问其他锁锁定的同步代码块

三、线程同步之Sysnchronized关键字的更多相关文章

  1. 多线程,线程同步,synchronized关键字的用法

    一.什么是多线程 Java多线程实现方式主要有四种:继承Thread类.实现Runnable接口.实现Callable接口通过FutureTask包装器来创建Thread线程.使用ExecutorSe ...

  2. MFC线程(三):线程同步事件(event)与互斥(mutex)

    前面讲了临界区可以用来达到线程同步.而事件(event)与互斥(mutex)也同样可以做到. Win32 API中的线程事件 HANDLE hEvent = NULL; void MainTestFu ...

  3. Java:多线程,线程同步,synchronized关键字的用法(同步代码块、非静态同步方法、静态同步方法)

    关于线程的同步,可以使用synchronized关键字,或者是使用JDK 5中提供的java.util.concurrent.lock包中的Lock对象.本文探讨synchronized关键字. sy ...

  4. java笔记--关于线程同步(7种同步方式)

    关于线程同步(7种方式) --如果朋友您想转载本文章请注明转载地址"http://www.cnblogs.com/XHJT/p/3897440.html"谢谢-- 为何要使用同步? ...

  5. JAVA中线程同步的方法(7种)汇总

    同步的方法: 一.同步方法 即有synchronized关键字修饰的方法. 由于java的每个对象都有一个内置锁,当用此关键字修饰方法时, 内置锁会保护整个方法.在调用该方法前,需要获得内置锁,否则就 ...

  6. java 多线程总结篇3之——生命周期和线程同步

    一.生命周期 线程的生命周期全在一张图中,理解此图是基本: 线程状态图 一.新建和就绪状态 当程序使用new关键字创建了一个线程之后,该线程就处于新建状态,此时它和其他的Java对象一样,仅仅由Jav ...

  7. Java:多线程,线程同步,同步锁(Lock)的使用(ReentrantLock、ReentrantReadWriteLock)

    关于线程的同步,可以使用synchronized关键字,或者是使用JDK 5中提供的java.util.concurrent.lock包中的Lock对象.本文探讨Lock对象. synchronize ...

  8. java中线程同步的几种方法

    1.使用synchronized关键字 由于java的每个对象都有一个内置锁,当用此关键字修饰方法时, 内置锁会保护整个方法.在调用该方法前,需要获得内置锁,否则就处于阻塞状态. 注: synchro ...

  9. java笔记--关于线程同步(5种同步方式)【转】

    为何要使用同步?     java允许多线程并发控制,当多个线程同时操作一个可共享的资源变量时(如数据的增删改查),      将会导致数据不准确,相互之间产生冲突,因此加入同步锁以避免在该线程没有完 ...

随机推荐

  1. log4j分离日志输出 自定义过滤 自定义日志文件

    普通的log4j.properties 定义: ### set log levels ### log4j.rootLogger = debug,D,E ## Disable other log log ...

  2. Java MD5机密算法的使用

    MD5 是常用的加密算法,是不可逆的.既只能加密,但不能解密. package cn.com.ctsi.csdp.base.util; import java.security.MessageDige ...

  3. XPath 学习二: 语法

    XPath 使用路径表达式来选取 XML 文档中的节点或节点集.节点是通过沿着路径 (path) 或者步 (steps) 来选取的. 下面列出了最有用的路径表达式: 表达式 描述 nodename 选 ...

  4. ASP.NET MVC4 URL传递汉字参数不能正确接收

    前两天写了个项目,在chrome上做的开发和测试. 拿给了产品,产品使用IE8.7.6进行测试的时候,发现很多报错.原因是URL里面的汉字在后台接收时显示的时乱码. 百度之~~ 最终解决方案, 在WE ...

  5. ubuntu下非root用户下获得使用wireshark的权限

    在非root用户下不能使用wireshark用来抓包,所以需要进行以下操作: sudo groupadd wireshark sudo chgrp wireshark /usr/bin/dumpcap ...

  6. 记一次WinForm中屏蔽空格键对按钮的作用

    事件的起因是在做一个项目功能时,添加快捷键关闭声音,这个键最终选择了空格键,但是当按下空格键时,会把窗体中获取焦点的控件(比如按钮,文本框等)的单击事件触发,所以要屏蔽这个现象. 开始使用各种方法,在 ...

  7. jquery1.7.2的源码分析(二)

    jquery.extend jQuery.extend = jQuery.fn.extend = function () { var options, name, src, copy, copyIsA ...

  8. html5中画布和SVG的比较

    SVG是基于XML的图形语言,在DOM解析中其每个元素都是可以用的,这样就可以为SCG元素附加JavaScript事件处理器,实现更加丰富的效果. 在SVG中,每个被绘制的图形均被视为对象,如果SVG ...

  9. [Machine Learning] 梯度下降法的三种形式BGD、SGD以及MBGD

    在应用机器学习算法时,我们通常采用梯度下降法来对采用的算法进行训练.其实,常用的梯度下降法还具体包含有三种不同的形式,它们也各自有着不同的优缺点. 下面我们以线性回归算法来对三种梯度下降法进行比较. ...

  10. WPF程序将DLL嵌入到EXE的两种方法

    WPF程序将DLL嵌入到EXE的两种方法 这一篇可以看作是<Visual Studio 版本转换工具WPF版开源了>的续,关于<Visual Studio 版本转换工具WPF版开源了 ...