java多线程-synchronized
一、线程安全问题
多线程操作各自线程创建的资源的时候,不存在线程安全问题。但多线程操作同一个资源的时候就会出现线程安全问题。下例为两个线程操作同一个name资源时发生的问题。
class TestSyn { public static void main(String[] args) throws Exception {
Resource resource = new Resource();
new Thread() {
@Override
public void run() {
while (true) {
r.sayb();
}
}
}.start();
new Thread() {
@Override
public void run() {
while (true) {
r.sayq();
}
}
}.start();
}
} class Resource {
private String name; public void sayb() {
name = "bbb";
System.out.println(Thread.currentThread().getName() + name);//Thread-0打印bbb
} public void sayq() {
name = "qqqqqq";
System.out.println(Thread.currentThread().getName() + name);//Thread-0打印bbb
}
}
/**
*
Thread-1qqqqqq
Thread-1qqqqqq
Thread-0qqqqqq //其中一段错误信息,Thread-0线程也打印了qqqqqq
Thread-0bbb
Thread-0bbb
*/
问题出现过程:
Thread-0获取执行权执行name="bbb"。
Thread-1获得执行权执行name="qqqqqq"。
Thread-0重新获得执行权执行打印指令,这时Thread-0就打印出了qqqqqq。
二、synchronized代码块
如果name赋值,打印name是一个原子操作就可以避免线程安全问题。
java中synchronized可以标记一段代码,达到原子操作的效果。
- 当一个线程执行标记有synchronized代码时将获得该对象的锁,然后开始执行synchronized标记的代码。
- 每一个对象只有一个锁,因此其他线程无法获得该对象锁。
- 其他线程如果这时候也执行到了标记有synchronized的代码将阻塞,直到获得对象锁的线程执行完synchronized标记的代码。
- 然后持有锁的线程释放锁。
- 其他线程开始争夺锁,回到第1步。
synchronized标记代码有两种方式:
//synchronized代码块
class Resource {
private String name; public void sayb() {
synchronized (this){
name = "bbb";
System.out.println(Thread.currentThread().getName() + name);//Thread-0打印bbb
}
//...其他代码
} public void sayq() {
synchronized (this){
name = "qqqqqq";
System.out.println(Thread.currentThread().getName() + name);//Thread-0打印bbb
}
//...其他代码
}
}
//synchronized方法
class Resource {
private String name; public synchronized void sayb() {
name = "bbb";
System.out.println(Thread.currentThread().getName() + name);//Thread-0打印bbb
//...其他代码
} public synchronized void sayq() {
name = "qqqqqq";
System.out.println(Thread.currentThread().getName() + name);//Thread-0打印bbb
//...其他代码
}
}
上例中两个线程执行的是同一个对象的方法,因此他们抢夺同一个锁,一个线程执行的时候,另一个线程阻塞。
两种方法有些不同点:
- synchronized方法标记在非static方法上,线程获得的锁为this,例子中为resource对象。若标记在static方法上则线程获得的锁为Resource.class对象。
- synchronized标记在代码块上,可以由用户自己指定,而且代码块的范围也可以自己指定。因此synchronized代码块比synchronized方法更加灵活。
注意:
- 使用synchronized会降低性能,使用时尽量缩小synchronized标记的范围。
- synchronized不会死锁,异常抛出时虚拟机会释放锁。
三、monitor与锁的重入
class Test {
public static void main(String[] args) {
syn();
} private static synchronized void syn(){
synchronized (Test.class){
synchronized (Test.class){
synchronized (Test.class){
System.out.println(1);
}
}
}
}
}
- 虚拟机为每个对象分配了一个monitor。
- 前面说到当一个线程进入synchronized代码块,就获得了对象锁,实际上是monitor的计数器++。
- monitor的计数器>0时,线程获得锁,因此上面的代码monitor的计数器每次进入一个synchronized代码块monitor的计数器++,结束一个代码块monitor的计数器--。
- monitor的计数器=0时,线程才会释放锁。
这就是锁的重入。
java多线程-synchronized的更多相关文章
- Java 多线程 —— synchronized关键字
java 多线程 目录: Java 多线程——基础知识 Java 多线程 —— synchronized关键字 java 多线程——一个定时调度的例子 java 多线程——quartz 定时调度的例子 ...
- Java多线程synchronized同步
非线程安全问题 “非线程安全”问题存在于“实例变量”中,如果是方法内部的私有变量,则不存在“非线程问题”.也即是说,方法中的变量永远是线程安全的. 如果多个线程共同访问1个对象中的实例变量,则可能线程 ...
- JAVA多线程synchronized详解
Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 当两个并发线程访问同一个对象object中的这个synchronized(this)同 ...
- java 多线程 Synchronized方法和方法块 synchronized(this)和synchronized(object)的理解
synchronized 关键字,它包括两种用法:synchronized 方法和 synchronized 块. 1. synchronized 方法:通过在方法声明中加入 synchronized ...
- java 多线程 synchronized与lock的通信机制等问题,结合相应实例说明
1. 利用多线程实现如下需求: 写两个线程,一个线程打印1~52,另一个线程打印A~Z,打印顺序是12A34B...5152Z: 2. 使用synchronized 实现 public class T ...
- Java多线程-synchronized关键字
进程:是一个正在执行中的程序.每一个进程执行都有一个执行顺序.该顺序是一个执行路径,或者叫一个控制单元. 线程:就是进程中的一个独立的控制单元.线程在控制着进程的执行. 一个进程中至少有一个线程 Ja ...
- Java多线程synchronized关键字
synchronized关键字代表着同步的意思,在Java中被synchronized修饰的有三种情况 1.同步代码块 //锁为objsynchronized(obj){ while(true){ i ...
- Java 多线程 - Synchronized关键字
目录 1-Synchronized 关键字概述 2- Synchronized关键字作用域 3- Synchronized 原理(反编译指令解释) 正文 1-Synchronized 关键字概述 由于 ...
- java多线程:synchronized和lock比较浅析
转载:http://www.toutiao.com/a6392135944652587266/?tt_from=weixin&utm_campaign=client_share&app ...
随机推荐
- 黑盒测试实践--Day3 11.27
黑盒测试实践--Day3 今天完成任务情况: 收到小组紧急通知,作业要求更新了.组长召集大家在下午课后去开个短会,会议信息如下: 时间:11.27 晚上5:30 地点:东九楼501 会议内容: 学习了 ...
- 【Android学习】Android工程资源命名禁忌
在制作一个继续按钮时,将button的id设置为continue,发现报了错误,error: invalid symbol: 'continue' 一开始还以为是编码问题,后来百度之后才知道安卓And ...
- 用ActionBar的ActionProvider的时候报错:cannot be cast to android.view.ActionProvider
在用ActionBar的自定义ActionProvider的时候有时候会遇到以下的报错:
- Nginx配置 简单写了个
#user nobody;worker_processes 1; #error_log logs/error.log;#error_log logs/error.log notice;#error_l ...
- Office Diary(工作日记本)
Office Diary 是一款免费.绿色小巧的写日记和收集文档资料的软件,界面效仿Office Word ,支持Word中常用的文字编辑排版功能,可以作为Microsoft Office产品系列的强 ...
- zookeeper安装和使用 windows
的 Zookeeper 是以 3.4.5 这个稳定版本为基础,最新的版本可以通过官网 http://hadoop.apache.org/zookeeper/来获取,Zookeeper 的安装非常简单, ...
- 【bzoj4036】[HAOI2015]按位或 fmt+期望
Description 刚开始你有一个数字0,每一秒钟你会随机选择一个[0,2^n-1]的数字,与你手上的数字进行或(c++,c的|,pascal 的or)操作.选择数字i的概率是p[i].保证0&l ...
- python3+Django1.11+mysql5.7 MySQL DB API Drivers
The Python Database API is described in PEP 249. MySQL has three prominent drivers that implement th ...
- UICollectionView 如何定制每个Cell的Size
最新用UICollectionView遇到挺多坑,差点让我废寝忘食了,虽然UICollectionView 逼格比UITableView高,但是真正想定制起来,特别是刚开始是用,真麻痹的到处都是坑,弄 ...
- centos配置免密登录
一.准备工作 1.先准备两台centos机器.例如:192.168.1.100和192.168.1.101两台机器,配置101免密登录100 2.默认centos会自带ssh和stfp,机器未安装,请 ...