各位好久不见,今天我将会把synchronized 关键字的相关知识点进行总结学习,还需要把之前已经总结过的知识点再巩固学习。
synchronized 关键字
作用是保证一个时刻点上只有一个线程在执行,不会出现并发的情况,达到排队执行的目的。
用法:
对象锁、类锁和同步块。注意:synchronized 不能修改构造器、变量等,synchronized 支持重入
synchronized 特性
原子性:确保线程互斥的访问同步代码。synchronized保证只有一个线程拿到锁,进入同步代码块操作共享资源,因此具有原子性。
可见性:保证共享变量的修改能够及时可见。执行 synchronized时,会对应执行 lock 、unlock原子操作。lock操作,就会清空工作空间该变量的值;执行unlock操作之前,必须先把变量同步回主内存中。
有序性:synchronized内的代码和外部的代码禁止排序,至于内部的代码,则不会禁止排序,但是由于只有一个线程进入同步代码块,因此在同步代码块中相当于是单线程的,根据 as-if-serial 语义,即使代码块内发生了重排序,也不会影响程序执行的结果。
悲观锁:synchronized是悲观锁。每次使用共享资源时都认为会和其他线程产生竞争,所以每次使用共享资源都会上锁。
独占锁(排他锁):synchronized是独占锁(排他锁)。该锁一次只能被一个线程所持有,其他线程被阻塞。
非公平锁:synchronized是非公平锁。线程获取锁的顺序可以不按照线程的阻塞顺序。允许线程发出请求后立即尝试获取锁。
可重入锁:synchronized是可重入锁。持锁线程可以再次获取自己的内部的锁。
同步实例方法:
修饰实例方法,作用域当前实例加锁,进入同步方法需要获取当前实例的锁。 方法上添加 synchronized 关键字,例如 public synchronized void show() 。
1、只要有一个线程进入了当前类对象的同步方法,则不允许其它线程再次进入当前对象的任何同步方法,但是允许进入非同步方法
2、同样当前线程可以进入当前类对象的其它同步方法(重入),也允许进入非同步方法。当线程进入同步方法,则获取同步锁,离开同步方法则自动释放锁
3、这个锁就是当前类对象
public class Account{
private Long id;
private Double balance;
public synchronized void withdraw(double number){
//...
}
public synchronized void disposit(double number){
//...
}
}
同步静态方法:
修改静态方法,作用于当前类对象加锁,进入同步静态方法需要获取当前类对象的锁。
public class NumOper {
private static int num=0;
public static synchronized void add(){
int cc=num;//缓存数据
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
cc++;
num=cc;
System.out.println("数据:"+cc);
}
public static void main(String[] args) {
Thread[] ts=new Thread[10];
for(int i=0;i<ts.length;i++){
ts[i]=new Thread(()->{ //构建 10 个 NumOper 对象,如果使用实例同步方法,则不能达到锁定的目的
NumOper no=new NumOper();
no.add();
});
ts[i].start();
}
for(Thread t:ts)
try {
t.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(NumOper.num);
}
}
同步代码块:
使用 synchronized 修饰代码块时同时指定加锁对象,对给定对象加锁,进入同步代码块的前提时获取指定对象的锁。建议在可能被并发访问的 goon 共享临界资源使用,通过这种方法可以保证并发线程在任何一个时刻只有线程可以进入修改共享的临界资源的代码块(临界区)。
public class App {
private static int num=0;
private Object lock;//充当锁的对象
public App(Object lock){
this.lock=lock;
}
public void add(){
synchronized (lock) { //同步代码块,可以是方法种的一部分代码,也可以是方法种的所有 代码,这里没有严格要求,synchronized 种的代码要求同步处理,不包含在 synchronized 种的方法不需 要同步处理。限制的颗粒都明显比方法还小
int cc=num;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
cc++;
num=cc;
System.out.println(cc);
}
}
}
好了,今天的知识点就先总结学习到这里吧,欢迎各位大神提出意见。
1220

被折叠的 条评论
为什么被折叠?



