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 ...
随机推荐
- 10 Scrapy框架持久化存储
一.基于终端指令的持久化存储 保证parse方法中有可迭代类型对象(通常为列表or字典)的返回,该返回值可以通过终端指令的形式写入指定格式的文件中进行持久化操作. 执行输出指定格式进行存储:将爬取到的 ...
- VUE项目中使用this.$forceUpdate()强制页面重新渲染
在使用Vue框架开发时,在函数中改变了页面中的某个值,在函数中查看是修改成功了,但在页面中没有及时刷新改变后的值,我是在使用多层v-for嵌套时出现这种问题的, 解决方法:运用 this.$force ...
- 网络初级篇之OSPF(一)原理
一.OSPF是什么 Open Shortest Path First, 开放最短路径优先协议,是一种开源的使用最短路径优先(SPF)算法的内部网关协议(IGP).常用于路由器的动态选路. 二.OSPF ...
- 英国电信选择由 Canonical 开发的 Ubuntu OpenStack 作为云平台
英国电信(简称 BT,British Telecom)宣布,选择由 Canonical 开发的 Ubuntu OpenStack 作为云平台,该平台将有助于支持引入 5G 和光纤到户的连接. 作为 U ...
- 完美解决Mysql的Access denied for user 'root'@'%的'问题
背景:mysql5.6 root已授权所有数据库,执行过下面的语句 grant all privileges on *.* to 'root'@'%' identified by 'root' 当使用 ...
- 小程序UI设计(5)-符合视觉规范-按钮视觉规范
在设计工具中,根据规范我们定义了大中小三种按钮的尺寸大:720rpx *94rpx 圆角10px 字体18中:360rpx*70rpx 圆角8px 字体16 文字距离两边最小60小:120rpx*60 ...
- Java语言基础(6)
1 while循环 案例:Demo1 1+2+3+4+5+...+100 = ? 首先定义一个变量sum,用来保存累加之和,int sum=0 第1次:sum = sum + 1 第2次: sum = ...
- mysql设置自增id清零 auto_increment
清空表数据之后,如何让自增id清零,即从0开始计数呢 ; 想让id从1开始,就让 AUTO_INCREMENT = 1 就行了.
- Mongodb的基本操作-数据库 集合 文档的增删改查
数据库操作: //查看有哪些数据库 > show dbs local 0.078GB mydb 0.078GB //use操作将切换到一个数据库 如果数据库存在将直接切换 如果不存在 那么 ...
- Acwing-282-石子合并(区间DP)
链接: https://www.acwing.com/problem/content/284/ 题意: 设有N堆石子排成一排,其编号为1,2,3,-,N. 每堆石子有一定的质量,可以用一个整数来描述, ...