java多线程系列1:Sychronized关键字
1.Synchronized使用范围:
同步普通方法:锁的是当前对象
//包含synchronized修饰的同步方法的类addCountClass
public class addCountClass { private int count = 0; synchronized public void addCount(String user)
{
try
{
if(user.equals("a"))
{
count = 100;
System.out.println("a set count = 100,over");
Thread.sleep(3000);
}else
{
count = 200;
System.out.println("b set count = 200,over");
}
System.out.println(user+" count = "+count); } catch (Exception e) {
e.printStackTrace();
} }
}
//线程类A
public class ThreadA extends Thread {
private addCountClass addcount1;
public ThreadA(addCountClass addcount)
{
super();
this.addcount1 = addcount;
} public void run()
{
super.run();
addcount1.addCount("a");
}
}
//线程类B
public class ThreadB extends Thread {
private addCountClass addcount2;
public ThreadB(addCountClass addcount)
{
super();
this.addcount2 = addcount;
} public void run()
{
super.run();
addcount2.addCount("b");
} }
//测试类
public class MainClass { public static void main(String[] args) { addCountClass addCount1 = new addCountClass();
addCountClass addCount2 = new addCountClass();
//线程th1启动后,调用addCount方法时,是用对象addCount1来调用的
Thread th1 = new ThreadA(addCount1); //线程th2启动后,调用addCount方法时,是用对象addCount2来调用的
Thread th2 = new ThreadB(addCount2); th1.start();
th2.start(); } }
//输出结果
a set count = 100,over
b set count = 200,over
b count = 200
a count = 100 /*分析上述结果可知,因为类中Synchronized关键字修饰的是普通方法,
*因此锁定的是当前的对象,所以两次调用时分别锁定了addCount1和
*addCount2,所以两个线程都能够正常访问,互不影响
*/
同步静态方法:锁的是当前class(类)对象
//将上一个例子中的addCount方法修改为类中的static方法
public class addCountClass { private static int count = 0; synchronized public static void addCount(String user)
{
try
{
if(user.equals("a"))
{
count = 100;
System.out.println("a set count = 100,over");
Thread.sleep(3000);
}else
{
count = 200;
System.out.println("b set count = 200,over");
}
System.out.println(user+" count = "+count); } catch (Exception e) {
e.printStackTrace();
}
}
}
//运行结果
a set count = 100,over
a count = 100
b set count = 200,over
b count = 200 /*
*此时可以看到,执行结果只可能是一个线程完全执行完addCount方法后
*另一个线程才能够进入该方法,这是因为此时Synchronized修饰的是类
*中的静态方法,因此锁定的当前的class对象,即当前类。因此无论是
*addCount1还是addCount2来调用addCount方法,都会锁定当前类对象
*/
同步代码块:锁的是()中的对象,synchronized(this)代码块也是锁定当前对象
当某个需要同步的方法中并不是所有的部分都需要同步时,可将需要同步的代码块用synchronized来修饰,可以提高程序并发效果。
//案例1,整个方法都加上了Syncchronized关键字
public class Task { private int a = 0;
synchronized public void longTimeTask()
{
//模拟一个长时间的无需同步的任务
System.out.println("no need Synchronized task start");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("no need Synchronized task end"); //需要同步的任务
System.out.println("Synchronized task start");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Synchronized task end");
}
}
//Thread类A
public class ThreadA extends Thread {
private Task task;
public ThreadA(Task task)
{
super();
this.task = task;
} public void run()
{
super.run();
task.longTimeTask();
}
}
public class ThreadB extends Thread {
private Task task;
public ThreadB(Task task)
{
super();
this.task = task;
} public void run()
{
super.run();
task.longTimeTask();
}
}
//测试类
public class MainClass2 { public static void main(String[] args) throws Exception {
long startTime = System.currentTimeMillis(); Task task = new Task();
Thread th1 = new ThreadA(task);
Thread th2 = new ThreadB(task); th1.start();
th2.start(); th2.join(); long totalTime = System.currentTimeMillis()-startTime;
System.out.println("程序总计用时:"+ totalTime); } }
//输出结果
no need Synchronized task start
no need Synchronized task end
Synchronized task start
Synchronized task end
no need Synchronized task start
no need Synchronized task end
Synchronized task start
Synchronized task end
程序总计用时:8006毫秒
分析上述结果可知,两个线程分别去调用加锁方法,第二个需要等到第一个执行完加锁方法中的全部步骤后才可进入执行,即使其中有一部分是无需线程同步的。
修改上述加锁部分,将Synchronized关键字只加到需要同步的代码块上:
public class Task { private int a = 0;
public void longTimeTask()
{
//模拟一个长时间的无需同步的任务
System.out.println("no need Synchronized task start");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("no need Synchronized task end"); //只在需要同步的任务前加上synchronized
synchronized(this)
{
System.out.println("Synchronized task start");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Synchronized task end");
}
}
}
最终程序执行结果为:
//程序运行结果
no need Synchronized task start
no need Synchronized task start
no need Synchronized task end
no need Synchronized task end
Synchronized task start
Synchronized task end
Synchronized task start
Synchronized task end
程序总计用时:5010毫秒
分析上述结果可知,此时线程th1和th2访问longTimeTask方法,但是其中一部分为无需线程同步的,两个线程可以并发执行,而加上了Sychronized方法的代码块。则会在第一个线程进入时加上
task对象锁,第二个线程进入该代码块时不能获取到该锁,所以该代码块无法并行,最终使用代码块加锁的方式,在不影响程序正常执行的情况下,提高了程序并发。
2.实现原理:JVM
是通过进入、退出对象监视器( Monitor
)来实现对方法、同步块的同步的。
具体实现是在编译之后在同步方法调用前加入一个 monitor.enter
指令,在退出方法和异常处插入 monitor.exit
的指令。
其本质就是对一个对象监视器( Monitor
)进行获取,而这个获取过程具有排他性从而达到了同一时刻只能一个线程访问的目的。
而对于没有获取到锁的线程将会阻塞到方法入口处,直到获取锁的线程 monitor.exit
之后才能尝试继续获取锁。
java多线程系列1:Sychronized关键字的更多相关文章
- [java基础]一文理解java多线程必备的sychronized关键字,从此不再混淆!
java并发编程中最长用到的关键字就是synchronized了,这里讲解一下这个关键字的用法和容易混淆的地方. synchronized关键字涉及到锁的概念, 在java中,synchronized ...
- Java多线程系列--“基础篇”04之 synchronized关键字
概要 本章,会对synchronized关键字进行介绍.涉及到的内容包括:1. synchronized原理2. synchronized基本规则3. synchronized方法 和 synchro ...
- Java多线程系列——原子类的实现(CAS算法)
1.什么是CAS? CAS:Compare and Swap,即比较再交换. jdk5增加了并发包java.util.concurrent.*,其下面的类使用CAS算法实现了区别于synchronou ...
- Java多线程系列——从菜鸟到入门
持续更新系列. 参考自Java多线程系列目录(共43篇).<Java并发编程实战>.<实战Java高并发程序设计>.<Java并发编程的艺术>. 基础 Java多线 ...
- Java多线程系列--“JUC锁”01之 框架
本章,我们介绍锁的架构:后面的章节将会对它们逐个进行分析介绍.目录如下:01. Java多线程系列--“JUC锁”01之 框架02. Java多线程系列--“JUC锁”02之 互斥锁Reentrant ...
- Java多线程系列目录(共43篇)
最近,在研究Java多线程的内容目录,将其内容逐步整理并发布. (一) 基础篇 01. Java多线程系列--“基础篇”01之 基本概念 02. Java多线程系列--“基础篇”02之 常用的实现多线 ...
- Java多线程系列--“JUC锁”06之 Condition条件
概要 前面对JUC包中的锁的原理进行了介绍,本章会JUC中对与锁经常配合使用的Condition进行介绍,内容包括:Condition介绍Condition函数列表Condition示例转载请注明出处 ...
- Java多线程系列--“基础篇”11之 生产消费者问题
概要 本章,会对“生产/消费者问题”进行讨论.涉及到的内容包括:1. 生产/消费者模型2. 生产/消费者实现 转载请注明出处:http://www.cnblogs.com/skywang12345/p ...
- Java多线程系列--“基础篇”05之 线程等待与唤醒
概要 本章,会对线程等待/唤醒方法进行介绍.涉及到的内容包括:1. wait(), notify(), notifyAll()等方法介绍2. wait()和notify()3. wait(long t ...
- Java多线程系列--“基础篇”06之 线程让步
概要 本章,会对Thread中的线程让步方法yield()进行介绍.涉及到的内容包括:1. yield()介绍2. yield()示例3. yield() 与 wait()的比较 转载请注明出处:ht ...
随机推荐
- Java中的Switch....case语句:
一.格式: switch(表达式){ case 常量表达式1: 语句1; case 常量表达式2: 语句2; … case 常量表达式n: 语句n; default: ...
- N1试卷常考词汇总结
免れる まぬがれる 免去,幸免 軽率 けいそつ 轻率,草率 捩れる ねじれる 拧劲儿,扭歪,弯曲 裂ける さける 裂开,破裂 避ける さける 躲避,避开 つまむ 挟,捏,掐 追及 ついきゅう 追上.追 ...
- linux中查看文件夹结构的小工具
tree命令是Linux/UNIX系统中常用的命令,可以非常方便地查看文件夹的结构,并且以树形目录的形式展示 在Ubuntu中安装 sudo apt-get install tree 在CentOS中 ...
- 用ant打包
Eclipse 内置了 Ant . Ant 是一种类似于批处理程序的软件包,它主要繁琐的工作是编写和调试自动处理脚本(一个 XML 文件),但只要有了这个脚本,我们就可以一键完成所有的设定工作. 本节 ...
- nginx学习第三章
一.系统环境 ubuntu6.4系统 nginx 版本: nginx/1.10.3 (Ubuntu). 二.打开目录浏览功能Nginx默认是不允许列出整个目录的.如需此功能,编辑虚拟主机配置文件,在l ...
- linux 用户及文件权限管理
Linux 是一个可以实现多用户登陆的操作系统,比如“李雷”和“韩梅梅”都可以同时登陆同一台主机,他们共享一些主机的资源,但他们也分别有自己的用户空间,用于存放各自的文件.但实际上他们的文件都是放在同 ...
- Codeforces Round #581 (Div. 2) B. Mislove Has Lost an Array (贪心)
B. Mislove Has Lost an Array time limit per test1 second memory limit per test256 megabytes inputsta ...
- 牛客练习赛46 B 华华送奕奕小礼物 (预处理前缀和,二分)
链接:https://ac.nowcoder.com/acm/contest/894/B?&headNav=acm 来源:牛客网 华华送奕奕小礼物 时间限制:C/C++ 1秒,其他语言2秒 空 ...
- 写一个基于TCP协议套接字,服务端实现接收客户端的连接并发
''' 写一个基于TCP协议套接字,服务端实现接收客户端的连接并发 ''' client import socket import time client = socket.socket() clie ...
- Android 热修复(一)
名词: dex:java文件编译class 然后生成 dex文件在Android上运行: 1.dex分包: 2.找出出现问题的dex文件进行替换操作 3.下载dex文件,静默替换有问题的dex文件,进 ...