对于synchronized的理解
一、synchronized
同步关键字,分为同步代码块和同步函数
二、对synchronized的理解(未加static关键字)(以下所说:对同步方法和同步代码块均适用)
对象的创建是以类为模板的
1、两个并发的线程访问同一个类Object中的synchronized(this)同步代码块或者同步方法时,同一时间只能执行一个,另一个必须要等待当前线程执行完才能执行(同一个对象:见下面的testSynchronized,分为两个线程,两个线程访问的是一个方法)(一个对象两个线程一个方法)
例子:
public class TestSynchronized {
public void test1(){
synchronized(this) {
System.out.println("1"+this);
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
final TestSynchronized testSynchronized = new TestSynchronized();
final TestSynchronized testSynchronized1 = new TestSynchronized();
Thread thread1 = new Thread(new Runnable() { @Override
public void run() {
testSynchronized.test1();
}
},"test1");
Thread thread3 = new Thread(new Runnable() { @Override
public void run() {
testSynchronized.test1();
}
},"test3"); thread1.start();
thread3.start();
}
}
结果:
2、两个并发的线程访问同一个类Object中的synchronized(this)同步代码块或者同步方法时,两个交替进行,因为对象的创建是以类为模板的,所以两个对象都会有自己独立的方法(不同对象:testSynchronized和testSynchronized1,分为两个线程,两个线程访问的是一个方法)(两个对象两个线程一个方法)
例子:和第一个的例子相比仅仅修改了第31行
public class TestSynchronized {
public void test1(){
synchronized(this) {
System.out.println("1"+this);
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
final TestSynchronized testSynchronized = new TestSynchronized();
final TestSynchronized testSynchronized1 = new TestSynchronized();
Thread thread1 = new Thread(new Runnable() { @Override
public void run() {
testSynchronized.test1();
}
},"test1");
Thread thread3 = new Thread(new Runnable() { @Override
public void run() {
testSynchronized1.test1();
}
},"test3");
thread1.start();
thread3.start();
}
}
结果:
3、(两个线程同一对象)当一个线程已经访问了该类中的一个synchronized方法,另一个线程就不能再去访问访问其他的synchronized方法(对象锁是锁住了对象,所以只能执行完这个再去执行另一个)(一个对象两个线程两个方法)
例子:
public class TestSynchronized {
public void test1(){
synchronized(this) {
System.out.println("1"+this);
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public synchronized void test2(){
System.out.println(this);
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
final TestSynchronized testSynchronized = new TestSynchronized();
final TestSynchronized testSynchronized1 = new TestSynchronized();
Thread thread1 = new Thread(new Runnable() { @Override
public void run() {
testSynchronized.test1();
}
},"test1");
Thread thread2 = new Thread(new Runnable() { @Override
public void run() {
testSynchronized.test2();
}
},"test2");
thread1.start();
thread2.start();
}
}
结果:
4、(同一个对象)当一个线程已经访问了一个类的synchronized方法,那么另一个线程也可以访问其他的非synchronized方法,结果是交替进行的(一个对象两个线程两个方法[一个synchronized一个非synchronized的])
进行了同步的方法(加锁方法)和没有进行同步的方法(普通方法)是互不影响的,一个线程进入了同步方法,得到了对象锁,其他线程还是可以访问那些没有同步的方法(普通方法)
例子:
public class TestSynchronized {
public void test1(){
synchronized(this) {
System.out.println("1"+this);
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
//非synchronized
public void test2(){
System.out.println(this);
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
final TestSynchronized testSynchronized = new TestSynchronized();
final TestSynchronized testSynchronized1 = new TestSynchronized();
Thread thread1 = new Thread(new Runnable() { @Override
public void run() {
testSynchronized.test1();
}
},"test1");
Thread thread2 = new Thread(new Runnable() { @Override
public void run() {
testSynchronized.test2();
}
},"test2"); thread2.start();
thread1.start();
}
}
结果:
三、加了static后现成的执行
1、对于一个类,一个线程访问了加了static的synchronized方法,另一个线程同样可以访问未加static的synchronized方法,所以结果是交替进行,因为类和对象不同(static修饰后锁住的是类,所有对象共享,而没有加static锁住的是对象,只有每个对象私有)(一个对象一个类两个线程两个方法)
例子:
public class TestSynchronized {
public void test1(){
synchronized(this) {
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static synchronized void test2(){
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
final TestSynchronized testSynchronized = new TestSynchronized();
Thread thread1 = new Thread(new Runnable() { @Override
public void run() {
//对象调用的是该对象自己的方法
testSynchronized.test1();
}
},"test1");
Thread thread2 = new Thread(new Runnable() { @Override
public void run() {
//类调用的是类方法
TestSynchronized.test2();
}
},"test2");
thread2.start();
thread1.start();
}
}
结果:
2、两个都是被static修饰的synchronized方法,结果是一个线程等待另一个线程执行完才会执行,因为类是一样的(和同一个对象的理解差不多),方法被synchronized修饰只能一个执行完再执行另一个(一个类两个线程两个方法)
例子:
public class TestSynchronized {
public static void test1(){
synchronized(TestSynchronized.class) {
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static synchronized void test2(){
int i = 5;
while( i-- > 0) {
System.out.println(Thread.currentThread().getName() + " : " + i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
final TestSynchronized testSynchronized = new TestSynchronized();
Thread thread1 = new Thread(new Runnable() { @Override
public void run() {
TestSynchronized.test1();
}
},"test1");
Thread thread2 = new Thread(new Runnable() { @Override
public void run() {
TestSynchronized.test2();
}
},"test2"); thread2.start();
thread1.start();
}
}
结果:
补充:
面试的一道题:
一个只被synchronized修饰的方法fun(),现有两个对象a,b,分别是两个线程t1,t2
①a.fun()和b.fun()可以同时进行吗?
答:可以,因为是两个为不同的对象,对象的创建是以类为模板的,所以这两个对象中都会有自己的fun()方法,所以两个线程开启后会交替进行,如上面的二2
②回答完可以后,怎么可以让两个分开进行即一个完了之后再进行另一个?
答:给方法加上static关键字,static锁住了类,此时锁为“类锁”,所以虽然对象不一样但是类都是一样的,所以简单说就是一个类两个线程调用一个方法,肯定是一个执行完再执行另一个
对于synchronized的理解的更多相关文章
- Java中synchronized关键字理解
好记性不如烂笔头~~ 并发编程中synchronized关键字的地位很重要,很多人都称它为重量级锁.利用synchronized实现同步的基础:Java中每一个对象都可以作为锁.具体表现为以下三种形式 ...
- synchronized的理解
用法解释 synchronized是Java中的关键字,是一种同步锁.它修饰的对象有以下几种: 1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调 ...
- @synchronized深入理解
@synchronized是线程同步锁,易用.可读性高. @synchronized(self) { 临界区 } 利用如下命令将其重写 clang -rewrite-objc file 得到C++实 ...
- Java线程同步synchronized的理解
JVM中(留神:马上讲到的这两个存储区只在JVM内部与物理存储区无关)存在一个主内存(Main Memory),Java中所有的变量存储在主内存中,所有实例和实例的字段都在此区域,对于所有的线程是共享 ...
- synchronized(this) 与 synchronized(class) 理解
1.概念 synchronized 是 Java 中的关键字,是利用锁的机制来实现同步的. 锁机制有如下两种特性: 互斥性:即在同一时间只允许一个线程持有某个对象锁,通过这种特性来实现多线程中的协调机 ...
- java并发编程--Synchronized的理解
synchronized实现锁的基础:Java中每一个对象都可以作为锁,具体表现为3种形式. (1)普通同步方法,锁是当前实例对象 (2)静态同步方法,锁是当前类的Class对象 (3)同步方法块,锁 ...
- 【多线程与高并发原理篇:4_深入理解synchronized】
1. 前言 越是简单的东西,在深入了解后发现越复杂.想起了曾在初中阶段,语文老师给我们解说<论语>的道理,顺便给我们提了一句,说老子的无为思想比较消极,学生时代不要太关注.现在有了一定的生 ...
- volatile synchronized AtomicInteger的区别
在网络上看了很多关于他们两个的区别与联系,今天用自己的话表述一下: synchronized 容易理解,给一个方法或者代码的一个区块加锁,那么需要注意的是,加锁的标志位默认是this对象,当然聪明的你 ...
- Synchronized用法原理和锁优化升级过程(面试)
简介 多线程一直是面试中的重点和难点,无论你现在处于啥级别段位,对synchronized关键字的学习避免不了,这是我的心得体会.下面咱们以面试的思维来对synchronized做一个系统的描述,如果 ...
随机推荐
- Selenium+java - 日期控件的处理
前言 一般的日期控件都是input标签下弹出来的,设置日期使用selenium中的sendKeys 方法就可以解决. 但是我们也会碰到下面的时间日期控件(这个时候这个文本框是不允许我们输入时间的)如图 ...
- [Spring cloud 一步步实现广告系统] 16. 增量索引实现以及投送数据到MQ(kafka)
实现增量数据索引 上一节中,我们为实现增量索引的加载做了充足的准备,使用到mysql-binlog-connector-java 开源组件来实现MySQL 的binlog监听,关于binlog的相关知 ...
- elk系列教程:docker中安装配置elk
elasticSearch Docker安装elasticsearch: docker pull docker.io/elasticsearch:7.2.0 启动: docker run -p 920 ...
- 图解SSH隧道功能
SSH能够对SSH客户端与服务器端之间的网络通信提供加密功能,而且SSH的端口转发功能还能将其它TCP端口的网络数据通过SSH连接来转发,并且自动提供相应的加密和解密服务,这一过程也被称为“隧道”(t ...
- android ——Intent
Intent是android程序中各组件之间进行交互的重要方式,它可以用于指明当前组件想要执行的动作,也可以在不同组件之间传递数据,Intent一般被用于启动活动,启动服务以及发送广播. 一.显式的使 ...
- C#_会员管理系统
https://www.cnblogs.com/start-from-scratch/p/5420588.html
- Re-Architecting the Video Gatekeeper(二)
原文: https://medium.com/netflix-techblog/re-architecting-the-video-gatekeeper-f7b0ac2f6b00 想法 我们决定部署一 ...
- gunicorn 基础配置使用
flask 自带的 web 服务器稳定性较差,只能用于测试.最近做的 web 项目,每次启动,需要敲一堆参数文件,今天学习了官方文档里关于配置的说明,记录一下. 创建一个 gunicorn.conf ...
- 决策树ID3原理及R语言python代码实现(西瓜书)
决策树ID3原理及R语言python代码实现(西瓜书) 摘要: 决策树是机器学习中一种非常常见的分类与回归方法,可以认为是if-else结构的规则.分类决策树是由节点和有向边组成的树形结构,节点表示特 ...
- 基于UDP的socket tcp和udp的区别(小白进击篇)
目录 16.基于udp协议的socket通信 为什么udp不会有粘包现象 DGRAM datagram#数据报文 发送sento (发送的信息,发送给的地址) 接收revefrom 客户端 服务端 t ...