多线程同步锁和死锁以及synchronized与static synchronized 的区别
线程:线程是进程中的一个执行单元,负责当前进程中程序的执行,一个进程中至少有一个线程。一个进程中是可以有多个线程的,这个应用程序也可以称之为多线程程序。简而言之:一个程序运行后至少有一个进程,一个进程中可以包含多个线程。什么是多线程呢?即就是一个程序中有多个线程在同时执行。
单线程程序:即,若有多个任务只能依次执行。当上一个任务执行结束后,下一个任务开始执行。如,去网吧上网,网吧只能让一个人上网,当这个人下机后,下一个人才能上网。
多线程程序:即,若有多个任务可以同时执行。如,去网吧上网,网吧能够让多个人同时上网。
程序运行原理
分时调度
所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间。
抢占式调度
优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个(线程随机性),Java使用的为抢占式调度。
大部分操作系统都支持多进程并发运行,现在的操作系统几乎都支持同时运行多个程序。比如:现在我们上课一边使用编辑器,一边使用录屏软件,同时还开着画图板,dos窗口等软件。此时,这些程序是在同时运行,”感觉这些软件好像在同一时刻运行着“。
实际上,CPU(中央处理器)使用抢占式调度模式在多个线程间进行着高速的切换。对于CPU的一个核而言,某个时刻,只能执行一个线程,而 CPU的在多个线程间切换速度相对我们的感觉要快,看上去就是在同一时刻运行。
其实,多线程程序并不能提高程序的运行速度,但能够提高程序运行效率,让CPU的使用率更高。
线程安全
如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
/**
*
* @author LYJ
* 实现Runnable的代码
*
*/
public class Ticket implements Runnable {
//设置总票数为100,这里的ticket是成员变量,
//由于在测试类中new了一次,所以值存在一个,被三个售票窗口共享
int ticket=100;
public void run() {
//模拟售票
while(true) {
//如果票数大于0,继续售票
if(ticket>0) {
//为了让线程安全问题效果明显些,加入线程定时休眠Thread.sleep()
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//Thread.currentThread()是线程获取当前线程对象的方法 getName()获取调用者的线程名
System.out.println(Thread.currentThread().getName()+"正在售票:"+ticket--);
}
} } /**
*
* 开启多线程的代码
*
*/
public class ThreadDemo01 {
public static void main(String[] args) {
//创建Ticket的Runnable对象
Ticket ticket = new Ticket();
//创建线程3个对象模拟三个售票窗口,并把Runnable对象加入Thread和给Thread命名
new Thread(ticket,"窗口1").start();;
new Thread(ticket,"窗口2").start();;
new Thread(ticket,"窗口3").start();; }
*****************************************************************
输出结果:
窗口3正在售票:3
窗口2正在售票:2
窗口1正在售票:1
窗口3正在售票:0
窗口2正在售票:-1
结果中出现了负数和0,这就是线程安全问题,要怎么解决呢?
加同步锁 synchronized(Object o){....} o可以是任意对象
******************************************************************************
加入同步锁后的代码
public class Ticket implements Runnable {
//设置总票数为100,这里的ticket是成员变量,
//由于在测试类中new了一次,所以值存在一个,被三个售票窗口共享
int ticket=100;
public void run() {
//模拟售票
while(true) {
//如果票数大于0,继续售票 //加入同步锁
synchronized(this) {
if(ticket>0) {
//为了让线程安全问题效果明显些,加入线程定时休眠Thread.sleep()
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//Thread.currentThread()是线程获取当前线程对象的方法 getName()获取调用者的线程名
System.out.println(Thread.currentThread().getName()+"正在售票:"+ticket--);
}
}
} }
**********************************************
运行几次,发现运行结果中没有出现负数和0
同步方法:在方法声明上加上synchronized
public synchronized void method(){
可能会产生线程安全问题的代码
}
同步方法中的锁对象是 this(即调用者对象)
静态同步方法: 在方法声明上加上static synchronized
public static synchronized void method(){
可能会产生线程安全问题的代码
}
静态同步方法中的锁对象是 类名.class(因为在加载类文件的时候,静态同步方法由于是静态的也被加载进内存了,类名.class的加载优先级高于静态方法)
同步代码块:在需要同步的代码外面包上一个synchronized
(Object o){
可能会产生线程安全问题的代码
}
同步代码块中的所对象可以是任意对象
死锁
同步锁使用的弊端:当线程任务中出现了多个同步(多个锁)时,如果同步中嵌套了其他的同步。这时容易引发一种现象:程序出现无限等待,这种现象我们称为死锁。这种情况能避免就避免掉。
synchronzied(A锁){
synchronized(B锁){
}
}
/**
*
*创建锁对象
*
*/
public class Lock {
//这里用private封装,为了不让外面随便造锁,限制只能有A,B锁个一把,这样容易出现死锁
//即A同学和B同学想相互串门,可是没人只有一把自己房间的钥匙,而且各自都不愿意先给,于是死锁
private Lock() {};
public static final Object lockA =new Object();
public static final Object lockB = new Object();
//这里使用static 为了让外界可以通过类名调用成员变量lockA和lockB
//因为外面无法创建Lock对象,为了让外面在不创对象的情况下调用,加了static,通过类名加变量名访问
}
/**
* 线程任务类
*
*/
import java.util.Random;
public class ThreadTask implements Runnable {
int x = new Random().nextInt(1);//用随机数随机获取0、1,来模拟CPU随机分配执行权的行为
@Override
public void run() {
while(true) {
if(x%2==0) {
//情况一
// 先执行A再执行B:即A同学先拿了A门的钥匙去开A门,然后打算开B门
synchronized(Lock.lockA) {
System.out.println("A同学...开A门");
synchronized(Lock.lockB) {
System.out.println("A同学...开B门");
}
}
}else {
//情况二
// 先执行B执行A:B同学先拿了B门的钥匙,去开B门,然后打算开A门
synchronized(Lock.lockB) {
System.out.println("B同学...开B门");
synchronized(Lock.lockA) {
System.out.println("B同学...开A门");
}
}
}
x++;
}
}
/**
*
* 线程测试类
*
*/
public class ThreadDemo {
public static void main(String[] args) {
//创建Runnable的实现类对象
ThreadTask tt = new ThreadTask();
//把Runnable实现类对象加入线程中,创建2个线程
Thread t1 = new Thread(tt);
Thread t2 = new Thread(tt);
t1.start();
t2.start();
}
*********************************************************
输出结果:A同学...开A门
A同学...开B门
B同学...开B门
B同学...开A门
A同学...开A门
B同学...开B门
结论:A同学或者B同学,一个人先后拿走两把钥匙时,线程是正常运行的,一旦A拿了A锁进去A门的时候,CPU突然让B开始执行,让B拿了B锁进入B门,结果A需要B锁,B也需要A锁,两者又不能后退
于是死锁现象发生了。
等待唤醒机制
线程之间的通信:多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同。通过一定的手段使各个线程能有效的利用资源。而这种手段即等待唤醒机制
synchronized与static synchronized 的区别
synchronized是对类的当前实例进行加锁,防止其他线程同时访问该类的该实例的所有synchronized块,注意这里是“ 类的当前实例 ”,类的两个不同实例就没有这种约束了。那么static synchronized恰好就是要控制类的所有实例的访问了,static synchronized是限制线程同时访问jvm中该类的所有实例同时访问对应的代码块。实际上,在类中某方法或某代码块中有 synchronized,那么在生成一个该类实例后,该类也就有一个监视块,放置线程并发访问该实例synchronized保护块, 而 static synchronized 则是所有该类的实例公用一个监视块了 ,也就是两个的区别了,也就是synchronized相当于this.synchronized,而staticsynchronized相当于Something.synchronized.
pulbic class Something(){
public synchronized void isSyncA(){}
public synchronized void isSyncB(){}
public static synchronized void cSyncA(){}
public static synchronized void cSyncB(){}
}
注解:该列子来自一个日本作者-结成浩的《java多线程设计模式》
那么,假如有Something类的两个实例a与b,那么下列组方法何以被1个以上线程同时访问呢
a. x.isSyncA()与x.isSyncB()
b. x.isSyncA()与y.isSyncA()
c. x.cSyncA()与y.cSyncB()
d. x.isSyncA()与Something.cSyncA()
这里,很清楚的可以判断:
a,都是对同一个实例的synchronized域访问,因此不能被同时访问
b,是针对不同实例的,因此可以同时被访问
c,因为是staticsynchronized,所以不同实例之间仍然会被限制,相当于Something.isSyncA()与 Something.isSyncB()了,因此不能被同时访问。
那么,第d呢?,书上的 答案是可以被同时访问的,答案理由是synchronzied的是实例方法与synchronzied的类方法由于锁定(lock)不同的原因。
个人分析也就是synchronized 与static synchronized 相当于两帮派,各自管各自,相互之间就无约束了,可以被同时访问。 后面一部分将详细分析 synchronzied 是怎么样实现的 。
结论 :
A: synchronized static是某个类的范围,synchronized static cSync{}防止多个线程同时访问这个类中的synchronized static 方法。它可以对类的所有对象实例起作用。
B: synchronized 是某实例的范围,synchronized isSync(){}防止多个线程同时访问这个实例中的synchronized 方法。
2、synchronized方法与synchronized代码快的区别 synchronizedmethods(){}与 synchronized(this){}之间没有什么区别,只是 synchronized methods(){} 便于阅读理解,而 synchronized ( this){}可以更精确的控制冲突限制访问区域,有时候表现更高效率。
3 、synchronized
关键字是不能继承的
也就是说,基类的方法synchronized f(){} 在继承类中并不自动是synchronized f(){},而是变成了f(){}。继承类需要你显式的指定它的某个方法为synchronized方法;
4、从源代码详细理解synchronized关键字(参考Observable类源码)
Java中的Observer模式,看了其中的Observable类的源码,发现里面几乎所有的方法都用了synchronized关键字(不是全部),其中个别用了synchronized(this){}的区块
多线程同步锁和死锁以及synchronized与static synchronized 的区别的更多相关文章
- 第十五章、Python多线程同步锁,死锁和递归锁
目录 第十五章.Python多线程同步锁,死锁和递归锁 1. 引子: 2.同步锁 3.死锁 引子: 4.递归锁RLock 原理: 不多说,放代码 总结: 5. 大总结 第十五章.Python多线程同步 ...
- synchronized与static synchronized 的差别、synchronized在JVM底层的实现原理及Java多线程锁理解
本Blog分为例如以下部分: 第一部分:synchronized与static synchronized 的差别 第二部分:JVM底层又是怎样实现synchronized的 第三部分:Java多线程锁 ...
- Java面试之synchronized 和 static synchronized
面试题: 答案: 不能 不能 不能 不能 能 正文 概述 通过分析这两个用法的分析,我们可以理解java中锁的概念.一个是实例锁(锁在某一个实例对象上,如果该类是单例,那么该锁也具有全局锁的概念), ...
- Synchronized和Static Synchronized区别
通过分析这两个用法的分析,我们可以理解Java中锁的概念. 一个是实例锁(锁在某一个实例对象上,如果该类是单例,那么该锁也具有全局锁的概念), 一个是全局锁(该锁针对的是类,无论实例多少个对象,那么线 ...
- 浅析Java中synchronized与static synchronized
synchronized关键字 synchronized是进行同步处理而保证线程安全.在一个方法中,如果是方法内的私有变量,那个这个变量是线程安全的,但是类中的实例变量是可能会出现线程安全问题的,当多 ...
- [Android Pro] synchronized与static synchronized 的区别
reference to : http://www.cnblogs.com/shipengzhi/articles/2223100.html 1.synchronized与static synchr ...
- synchronized和static synchronized的比较
群里讨论的一个问题,网上别人已经贴出了很详细的说明,这里补充记录下,后面加入个人测试代码. 起因:1月份的时候看群里讨论一道问题,问题内容如下: 一个日本作者-结成浩的<java多线程设计模式& ...
- synchronized与static synchronized 差异
1.synchronized与static synchronized 差异 synchronized是对类的当前实例进行加锁,防止其它线程同一时候訪问该类的该实例的全部synchroniz ...
- 起底多线程同步锁(iOS)
iOS/MacOS为多线程.共享内存(变量)提供了多种的同步解决方案(即同步锁),对于这些方案的比较,大都讨论了锁的用法以及锁操作的开销,然后就开销表现排个序.春哥以为,最优方案的选用还是看应用场景, ...
随机推荐
- 前端常用的库和实用技术之JavaScript高级技巧
javascript高级技巧 变量作用域和闭包 <!DOCTYPE html> <html lang="en"> <head> <meta ...
- Android开发 AndroidStudio解决Error:moudle not specified
问题描述 在使用Android Studio 进行Builder APKs的时候,如果发现无法degub, 进行配置的时候 没有module可以进行指定 问题原因 项目未与Grade Files 文件 ...
- redis和ehcache的区别,存储方式(各属于内存还是外存)
ehcache属于内存存储,redis的缓存属于内存存储,redis的持久文件属于外存存储: redis是通过socket访问到缓存服务,效率比ecache低,比数据库要快很多,处理集群和分布式缓存方 ...
- Redis过滤器如何与Envoy代理一起使用
1.克隆源码到机器 [root@cx-- ~]# git clone https://github.com/envoyproxy/envoy Cloning into 'envoy'... remot ...
- C++——多态
1. 多态定义的构成条件 多态是在不同继承关系的类对象,去调同一函数,产生了不同的行为. 就是说,有一对继承关系的两个类,这两个类里面都有一个函数且名字.参数.返回值均相同,然后我们通过调用函数来实现 ...
- python非对称加密模块rsa
一.代码 # 导入rsa库 import rsa.common class RSA(object): def __init__(self): self.key= rsa.newkeys(256) se ...
- 在Laravel5.4中自动加载自定义文件
目标:想要在TestController.php中使用自定义的/app/Common/test.php中的test()函数. 1.在app文件夹下创建文件app/Common/test.php,文件内 ...
- 求N!中素数的个数
int degree_in_fact(int n, int x)//求n!中素数x的次数 { if(m) return degree_in_fact(n/x,x)+n/x; ; }
- JS中鲜为人知的问题: [] == ![]结果为true,而 {} == !{}却为false
console.log( [] == ![] ) // true console.log( {} == !{} ) // false 在比较字符串.数值和布尔值的相等性时,问题还比较简单.但在涉及到对 ...
- 13-7-return的高级使用
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...