Java synchronized的使用
需要明确的几个问题:
synchronized关键字可以作为函数的修饰符,也可作为函数内的语句,也就是平时说的同步方法和同步语句块。如果 再细的分类,synchronized可作用于instance变量、object reference(对象引用)、static函数和class literals(类名称字面常量)身上。
无论synchronized关键字加在方法上还是对象上,它取得的锁都是对象,而不是把一段代码或函数当作锁――而且同步方法很可能还会被其他线程的对象访问。
每个对象只有一个锁(lock)与之相关联。
实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
synchronized关键字的作用域有二种:
某个对象实例内,synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法(如果一个对象有多个synchronized方法,只要一个线 程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。这时,不同的对象实例的 synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法;
某个类的范围,synchronized static aStaticMethod{}防止多个线程同时访问这个类中的synchronized static 方法。它可以对类的所有对象实例起作用。
1、使用在方法上synchronized aMethod(){...}
使用相同的 object
public class synchTest {
private String a= "";
private ListString b= new ArrayList();
// 方法一
public void job() {
System.out.println("job .....");
synchronized (b){
System.out.println("job 使用锁中 ....");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
}
System.out.println("job end.....");
}
// 方法二
public synchronized void job2(){
System.out.println("job2 .....");
synchronized (b){
System.out.println("job22 使用锁中 ...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
}
System.out.println("job2 end.....");
}
public static void main(String[] args) {
final synchTest rs = new synchTest();
new Thread() {
public void run() {
rs.job();
}
}.start();
new Thread() {
public void run() {
rs.job2();
}
}.start();
}
}
结果:
job .....
job 使用锁中 ....
job2 .....
job end.....
job22 使用锁中 ...
job2 end.....
View Code
使用不同的object
public class synchTest {
private String a= "";
private ListString b= new ArrayList();
// 方法一
public void job() {
System.out.println("job .....");
synchronized (a){
System.out.println("job 使用锁中 ....");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
}
System.out.println("job end.....");
}
// 方法二
public synchronized void job2(){
System.out.println("job2 .....");
synchronized (b){
System.out.println("job22 使用锁中 ...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
}
System.out.println("job2 end.....");
}
public static void main(String[] args) {
final synchTest rs = new synchTest();
new Thread() {
public void run() {
rs.job();
}
}.start();
new Thread() {
public void run() {
rs.job2();
}
}.start();
}
}
结果:
job .....
job 使用锁中 ....
job2 .....
job22 使用锁中 ...
job end.....
job2 end.....
View Code
使用this关键词
public class synchTest {
private String a= "";
private ListString b= new ArrayList();
// 方法一
public void job() {
System.out.println("job .....");
synchronized (this){
System.out.println("job 使用锁中 ....");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
}
System.out.println("job end.....");
}
// 方法二
public synchronized void job2(){
System.out.println("job2 .....");
synchronized (b){
System.out.println("job22 使用锁中 ...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
}
System.out.println("job2 end.....");
}
public static void main(String[] args) {
final synchTest rs = new synchTest();
new Thread() {
public void run() {
rs.job();
}
}.start();
new Thread() {
public void run() {
rs.job2();
}
}.start();
}
}
结果:
job .....
job 使用锁中 ....
job end.....
job2 .....
job22 使用锁中 ...
job2 end.....
View Code
结论:
synchronized(Object) object相同的情况下,修饰的内容会同步,等上一个执行完才能执行下一个方法的内容
synchronized(Object)object不相同的情况下,修饰内容不会同步,两个方法可以一起执行
this这个比较特殊,如果先执行修饰this这个方法的内容,会同步,否则 不会同步(可以测试下)
2、使用在方法内部synchronized(Oject){...}
public class synchTest {
// 方法一
public synchronized void job() {
System.out.println("job .....");
System.out.println("job 使用锁中 ....");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
System.out.println("job end.....");
}
// 方法二
public synchronized void job2(){
System.out.println("job2 .....");
System.out.println("job22 使用锁中 ...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
System.out.println("job2 end.....");
}
public static void main(String[] args) {
final synchTest rs = new synchTest();
new Thread() {
public void run() {
rs.job();
}
}.start();
new Thread() {
public void run() {
rs.job2();
}
}.start();
}
}
结果:
job .....
job 使用锁中 ....
job end.....
job2 .....
job22 使用锁中 ...
job2 end.....
View Code
结论:
对象实例内,synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法,在对象内容所有的synchronized 的方法都会同步,必须等上一个方法执行完才能执行下一个方法
2、使用在方法内部synchronized(Oject){...}、synchronized aMethod(){...}混用
public class synchTest {
public String a = "";
// 方法一
public void job() {
System.out.println("job .....");
synchronized (a){
System.out.println("job 使用锁中 ....");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
}
System.out.println("job end.....");
}
// 方法二
public synchronized void job2(){
System.out.println("job2 .....");
System.out.println("job22 使用锁中 ...");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
System.out.println("job2 end.....");
}
public static void main(String[] args) {
final synchTest rs = new synchTest();
new Thread() {
public void run() {
rs.job();
}
}.start();
new Thread() {
public void run() {
rs.job2();
}
}.start();
}
}
结果:
job .....
job 使用锁中 ....
job2 .....
job22 使用锁中 ...
job end.....
job2 end.....
View Code
结论:
对象实例内synchronized aMethod(){} 与synchronized(Object) 不会相互同步
Java synchronized的使用 相关文章
【Flutter 3-1】Flutter手把手教程UI布局和Widget——底部导航栏BottomNavigationBar使用
作者 | 弗拉德 来源 | 弗拉德(公众号:fulade_me) BottomNavigationBar BottomNavigationBar 和 BottomNavigationBarItem 配合来共同展示Flutter里面的底部状态栏,底部状态栏是在移动端很重要的控件。 先看一下 BottomNavigationBar 构造方法 BottomNaviga
Java序列化,看这篇就够了
1.什么是序列化 Java序列化是指把Java对象转换为字节序列的过程,而Java反序列化是指把字节序列恢复为Java对象的过程: 序列化: 对象序列化的最主要的用处就是在传递和保存对象的时候,保证对象的完整性和可传递性。序列化是把对象转换成有序字节流,以便在
如何获取指定模块下所有的类
前言 在使用 scrapy 时,运行爬虫仅需要通过 scrapy crawl 爬虫名 就可启动我们写好的爬虫,那么 scrapy 是如何通过名称找到爬虫类的呢通过分析源码可窥见一二,同时也可从中找出获取指定模块下的所有类的方法。 scrapy 源码分析 在 scrapy.spiderloader.Spi
SpringBoot配置文件说明
1.简介 在使用SpringBoot的时候肯定听说过SpringBoot可以做到零配置,其实创建SpringBoot确实可以做到零配置,它在内部其实帮你默认配置基础的参数,但是它确实配置方便,所以集成的配置参数都可以在SpringBoot提供的配置文件中自己设置,除了在SpringBoot提
Qt中的QThread:使用QSemaphore进行多线程数据同步
20210127:在生产者、消费者的方法中添加线程挂起方法QThread::usleep(10),使ui不卡。 20210128:在添加Track类(保存生产者Producer生成的每组数据),在ui界面中使用model-view同步显示生产者生成的数据,model-view不会对主线程造成卡顿。对消费者同样创
SpringBoot使用JSR303校验数据
JSR303是java提供的一套用来校验数据的规范 SpringBoot使用JSR303校验数据 javax.validation.constraints 使用方式: 在Entity实体类上加上相应的注解,并定义自定义message(错误提示) @Valid 启用校验 数据验证不通过: 状态码:400 可以在需要校验的对象后
SpringBoot-dev-tools的使用
spring为开发者提供了一个名为spring-boot-devtools的模块来使Spring Boot应用支持热部署,提高开发者的开发效率,无需手动重启Spring Boot应用。 在项目中添加 spring-boot-devtools 非常简单,只需要添加以下依赖项即可: maven dependencies dependency g
JavaScript数据类型转换
目录 前言 一、强制转换 1、其他的数据类型转换为String 方式一:toString()方法 方式二:String()函数 2、其他的数据类型转换为Number 方式一:使用Number()函数 方式二:parseInt() parseFloat() 3、其他的数据类型转换为Boolean 二、自动转换 1.自动转换
Go语言中的指针
与 Java 和 .NET 等编程语言不同,Go语言为程序员提供了控制数据结构指针的能力,但是,并不能进行指针运算。Go语言允许你控制特定集合的数据结构、分配的数量以及内存访问模式,这对于构建运行良好的系统是非常重要的。指针对于性能的影响不言而喻,如果你
JavaScript给对象赋值的两种方式
在JavaScript的基础语法中,我们必定会用到Object这种数据类型,给这种数据类型的属性赋值的方式有两种....... . 赋值的方式 var obj = { name: 'TOM', age: 18}obj.name = "Jack" 这应该是大家最常用的一种方式了,但是这种方式在有些特殊时候并不能够使用