
synchronized锁
锁的理解业务案例synchronized可重入synchronized方法异常理论知识
synchronized锁 锁的理解在下面代码中锁的是o,锁的底层。任何人执行都得先拿到o这把锁,锁定是锁定的某个对象
synchronized是具备原子性的
private final Object o = new Object();
public void m() {
synchronized (o) {
count--;
System.out.println(Thread.currentThread().getName() + "count=" + count);
}
}
以下代码中m_01和m_02以及m_03锁定是等值的
public void m_01() {
synchronized (this) {//m_01和m_02是等值的
count--;
System.out.println(Thread.currentThread().getName() + "count=" + count);
}
}
public synchronized void m_02() {//锁的是T01.class对象
count--;
System.out.println(Thread.currentThread().getName() + "count=" + count);
}
public void m_03() {//锁的是T01.class对象
synchronized (T01.class) {
count--;
System.out.println(Thread.currentThread().getName() + "count=" + count);
}
}
业务案例
设置值的时候采用synchronized,获取的时候不采用加锁的方式
//设置加锁 public synchronized void set(String name, BigDecimal balance) { this.name = name; try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } this.balance = balance; } //获取不加锁 public BigDecimal getBalance(String name) { return this.balance; } //容易产生脏读 public static void main(String[] args) { T03 t03 = new T03(); new Thread(() -> t03.set("zhangsan", BigDecimal.valueOf(100))).start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("第一次读取 zhangsan的金额为:" + t03.getBalance("zhangsan")); try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("第二次读取 zhangsan的金额为:" + t03.getBalance("zhangsan")); }
一个具有注脚的文本。1
synchronized是一把可重入锁。简单理解:调用m1获取一把锁,调用m2的时候发现是同一个线程,同样有锁,锁就是可重入的。
如果不可重入的话,导致第二个线程也需要获取锁。特别是涉及到继承的时候,如果子类继承父类。子类获取锁调用父类加锁的方法。会导致一直死锁。
synchronized void m1() {
System.out.println("m1 start");
m2();
System.out.println("m1 end");
}
synchronized void m2() {
System.out.println("m2 start");
}
public static void main(String[] args) {
new T04().m1();
}
synchronized方法异常
如果程序出现异常,锁会被释放、要是不想释放、这里可以让catch、继续执行。
如果抛出异常。会导致其他线程访问到上一个线程的数据。
int count = 1;
synchronized void m1() {
//try {
for (int i = 0; i < 10; i++) {
count++;
System.out.println("count数据=" + count);
if (i == 9) {
int j = count / 0;
}
}
count = 1;
//} catch (Exception e) {
// count = 1;
// e.printStackTrace();
//}
}
public static void main(String[] args) {
T05 t05 = new T05();
new Thread(() -> {
System.out.println("第一线程打印数据");
t05.m1();
}).start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(() -> {
System.out.println("第二线程打印数据");
t05.m1();
}).start();
}
理论知识
synchronized的底层实现
1.JDK早期、重量级,只要加锁都会去找 *** 作系统获取锁。
2.synchronized升级之后:markword 偏向锁(只有一个线程的时候,会偏向该线程)多个线程之后升级为自旋锁(旋10次之后)升级为重量锁去 *** 作系统获取锁
3.锁只能升级。不能降级
4.什么时候使用自旋锁,占用CPU,不访问 *** 作系统,加锁和解锁的动作下的
5.自旋锁用户态:不使用内核态。
6.执行时间短(加锁代码),线程数少,使用自旋锁
7.执行时间长、线程数多,用系统锁(Syn)
8.不能用String常量 Integer Long做synchronized因为会出现不同的方法使用该常量的。导致使用该常量就多次加锁,出现死锁等情况。
读取尽量不使用synchronized,毕竟使用加锁效率会降低10倍以上的。 ↩︎
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)