Java 多线程 - synchronize 关键字

学习自

http://cmsblogs.com/?p=2071

https://www.cnblogs.com/xrq730/p/4853713.html

synchronize 关键字的作用

synchronize关键字的作用是,使得本来是有操作的多线程在执行某些方法代码段 的时候,变得同步起来。即同一时间内只有一个线程能够访问,而且只有当该线程执行完成同步的代码之后,其他线程才能继续访问。

使用synchronize
  • 普通的同步方法 , 锁住的是当前类的实例对象this.
private synchronized void test() {
}
  • 静态同步方法,锁住的是当前类的字节码对象Class
private synchronized static void test2() {
}
  • 方法内的锁,锁住指定的对象
private synchronized void test3() {
synchronized (this) { }
}

通过 synchronize 来实现同步

@Override
public void call() {
new Thread(() -> print()).start();
new Thread(() -> print()).start();
}
/**
* Print
*/
private synchronized void print() {
for (int i = 0; i < 10; i++) {
Thread currentThread = Thread.currentThread();
System.out.printf("Current thread is %s : print %d \r\n", currentThread.getName(), i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//输出结果
Current thread is Thread-0 : print 0
Current thread is Thread-0 : print 1
Current thread is Thread-0 : print 2
Current thread is Thread-0 : print 3
Current thread is Thread-0 : print 4
Current thread is Thread-0 : print 5
Current thread is Thread-0 : print 6
Current thread is Thread-0 : print 7
Current thread is Thread-0 : print 8
Current thread is Thread-0 : print 9
Current thread is Thread-1 : print 0
Current thread is Thread-1 : print 1
Current thread is Thread-1 : print 2
Current thread is Thread-1 : print 3
Current thread is Thread-1 : print 4
Current thread is Thread-1 : print 5
Current thread is Thread-1 : print 6
Current thread is Thread-1 : print 7
Current thread is Thread-1 : print 8
Current thread is Thread-1 : print 9

从上面的打印中,我们能够看出来,只有当第一个线程执行完print 方法后第二个线程才会执行。这样的话就实现了线程的同步,在一些比较敏感的操作的时候一定要注意线程的同步,避免出现无法预料的错误。

死锁

synchronized 关键字虽然十分的强大,但是如果使用不当就会造成线程的死锁,造成严重的资源浪费。 而且线程死锁的情况,并不是每次都会出现,而是可能会发生死锁,尤其是在高并发的情况下。

造成死锁的原因

好,现在让我们回忆一下,西游记中流沙河的一个桥段。

孙悟空 : 妖怪,你敢上来吗。

沙悟净 : 你敢下来吗。

孙悟空 : 妖怪,你敢上来吗。

沙悟净 : 你敢下来吗。

.....

因为孙悟空 占据了陆地,沙悟净 想上陆地,但是上不去,因为打不过啊,而孙悟空想下海擒拿 沙悟净,但是也下不了海,因为沙悟净 占据了海下,再加上 孙猴子 水性不好,所以就一直在僵持着... -_-||。

上面的这个例子虽然有点生搬硬套的嫌疑,但是,这个例子,很想我们多线程死锁的清苦。

假设现在有 AB两个锁对象,并且有T1,T2 两个线程,当 T1 占据A对象等在B对象的同时,如果T2占据了B对象等待A对象的时候,因为T1占据了A对象,T1占据了B对象,T1等待B对象,T2等待A对象,但是T1所等在的B对象被T2占据了,而T2等待的A对象被T1所占据。这样相互的等待,就造成了线程的死锁。

死锁的例子
Object leftHand = new Object();
Object rightHand = new Object(); public void call() {
new Thread(() -> deadLock1()).start();
new Thread(() -> deadLock2()).start();
} /**
* 多线程的死锁
*/
private void deadLock1() {
synchronized (leftHand) {
//为了创造死锁的条件,让线程睡一会
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (rightHand) {
System.out.println("Right hand");
}
}
}
/**
* 多线程的死锁
*/
private void deadLock2() {
synchronized (rightHand) {
synchronized (leftHand) {
System.out.println("Left hand");
}
}
}

现在当我们运行程序的时候什么也不会打印出来,因为线程处于了死锁状态。

避免死锁

  • 注意枷锁的顺序,如果加锁的顺序是相同的,那么是不会发生死锁的。
  • 避免锁的嵌套
  • 通过Lock对象来加锁可以检测到死锁的情况,详细信息可以参考此博客, http://www.cnblogs.com/dolphin0520/p/3923167.html

Java 多线程 - synchronize 关键字的更多相关文章

  1. Java 多线程 —— synchronized关键字

    java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...

  2. Java 多线程 - Synchronized关键字

    目录 1-Synchronized 关键字概述 2- Synchronized关键字作用域 3- Synchronized 原理(反编译指令解释) 正文 1-Synchronized 关键字概述 由于 ...

  3. java多线程 -- volatile 关键字 内存 可见性

    内存可见性(Memory Visibility) 1 内存可见性(Memory Visibility)是指当某个线程正在使用对象状态而另一个线程在同时修改该状态,需要确保当一个线程修改了对象状态后,其 ...

  4. [Java多线程] volatile 关键字正确使用方法

    volatile 变量具有 synchronized 的可见性特性,但是不具备原子特性,即多线程环境中,使用 volatile 关键字的变量仅可以保证不同线程读取变量时,可以读到最新修改的变量值,但是 ...

  5. Java 多线程 - Volatile关键字

    作者: dreamcatcher-cx 出处: <http://www.cnblogs.com/chengxiao/> 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明 ...

  6. Java多线程synchronized关键字

    synchronized关键字代表着同步的意思,在Java中被synchronized修饰的有三种情况 1.同步代码块 //锁为objsynchronized(obj){ while(true){ i ...

  7. Java多线程-----volatile关键字详解

       volatile原理     Java语言提供了一种稍弱的同步机制,即volatile变量,用来确保将变量的更新操作通知到其他线程.当把变量声明为volatile类型后, 编译器与运行时都会注意 ...

  8. Java多线程——volatile关键字、发布和逸出

    1.volatile关键字 Java语言提供了一种稍弱的同步机制,即volatile变量.被volatile关键字修饰的变量不会被缓存在寄存器或者对其他处理器不可见的地方,因此在每次读取volatit ...

  9. Java多线程-synchronized关键字

    进程:是一个正在执行中的程序.每一个进程执行都有一个执行顺序.该顺序是一个执行路径,或者叫一个控制单元. 线程:就是进程中的一个独立的控制单元.线程在控制着进程的执行. 一个进程中至少有一个线程 Ja ...

随机推荐

  1. Intel 8086_通用寄存器|段寄存器

  2. sqoop的安装与配置

    最近需要将MySQL的数据导出到HDFS,所以搜到了sqoop2.跟sqoop1相比,sqoop2的好处是直接使用程序连接到集群上的sqoop,远程操作.流程是需要先创建link也可以理解成要操作的对 ...

  3. Hadoop生态圈-Flume的主流Sinks源配置

    Hadoop生态圈-Flume的主流Sinks源配置 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 本篇博客只是配置的是Flume主流的Sinks,想要了解更详细的配置信息请参考官 ...

  4. 转iOS UIAppearance使用详解

    iOS5及其以后提供了一个比较强大的工具UIAppearance,我们通过UIAppearance设置一些UI的全局效果,这样就可以很方便的实现UI的自定义效果又能最简单的实现统一界面风格,它提供如下 ...

  5. 一个Zabbix agent配置多个Zabbix Server

    环境说明: 公司和政府合作的项目中,需要对服务器添加监控.政府方面已对服务部署了zabbix agent,实现了系统层面的基础监控:而对于公司而言,需要对服务器上的服务进行监控,故需在原有的zabbi ...

  6. 如何使用 grunt

    1>. 首先要有nodejs环境, 至少0.8.0版本: 2>. 转到 项目文件夹下: >npm install –g grunt-cli >npm init #生成一个基本的 ...

  7. CString 与其它数据类型转换问题

    CString 头文件#include <afx.h> string 头文件#include <string.h> CString 转char * CString cstr; ...

  8. 洛谷 P3916 【图的遍历】反向加边+dfs

    前言: 对于这类带环的图,一般记忆化搜索不能很好的对所有遍历的边进行更新取值.因为环上的点可以相互到达,所以他们的答案因当是同步更新的,而dfs一旦你回溯完环上某个点就不会在更新这个点的答案了,做不到 ...

  9. MySQL5.6主从复制最佳实践

    MySQL5.6     主从复制的配置  环境 操作系统:CentOS-6.6-x86_64 MySQL 版本:mysql-5.6.26.tar.gz 主节点 IP:192.168.31.57    ...

  10. 无法执行该操作,因为链接服务器 "xxxxx" 的 OLE DB 访问接口 "SQLNCLI" 无法启动分布式事务

    在存储过程中使用事务,并且使用链接服务器时,报类似下面的错误 链接服务器"****"的 OLE DB 访问接口 "SQLNCLI10" 返回了消息 " ...