一定要会的synchronized关键字的用法
Posted Melody袁
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一定要会的synchronized关键字的用法相关的知识,希望对你有一定的参考价值。
synchronized(同步)关键字
修饰方法
- 修饰普通方法,锁的是当前实例对象
- 修饰静态方法,锁的是当前类的Class对象
修饰代码块,锁的是synchronized括号里的对象
public class SyncDemo1
//修饰普通方法
public synchronized void method()
//修饰静态方法
public static synchronized void staticMethod()
public void someMethod()
//同步代码块
//这里o是局部变量,外部不可能拿到,这种加锁是毫无意义的
Object o = new Object();
synchronized (o)
//o这个引用不能为null
synchronized是如何实现加锁的?-----以同步代码块为例
java中的所有对象在jvm实现的时候,内部都包含一把锁,这把锁默认情况下是打开的。
对象可以调用getClass()方法从对象拿到该对象的“类对象”。
同步代码块的理解
synchronized(ref)//加锁
一些语句;//加锁成功才能执行
//释放锁
普通同步方法的理解
//修饰普通方法
public synchronized void method()
//效果同上
public void method1()
synchronized (this)
静态同步方法的理解
//修饰静态方法
public static synchronized void staticMethod()
//效果同上
public void staticMethod1()
synchronized (SyncDemo1.class)
获取关于类的对象
- 类名.class
- 对象的引用.getClass
如果加锁失败,会怎么办?
(会触发线程调度隐含着必须执行操纵系统的代码才能完成这个工作,所有会有切换内核态的操作)
- 加锁失败之后没有资格继续执行代码
- 占据CPU没有意义
- 会触发线程调度,加锁失败的线程,会被调度器从CPU上调度下来
- 在锁打开之前,再分配CPU给该线程也没有意义
- 线程状态要变化(不是RUNNABLE)
- 线程状态编程BLOCKED(这个状态是专为sychronized加锁失败设置的专用状态)
- 为了准备好当锁释放时能找到该线程,把它叫回, 把线程加到这把锁的阻塞队列中(blocking queue)
易错点
哪些情况下会导致两个线程之间产生互斥
public class SyncDemo2
//没加锁
void method1()
//锁的时
synchronized void method2()
static synchronized void method3()
void method4()
synchronized (this)
static void method5()
synchronized (SyncDemo2.class)
void method6()
synchronized (SyncDemo2.class)
改造n++和n–操作,使得线程安全
只要保证同时加锁,加得是同一把锁,哪个对象都可以
锁得粒度会影响运行效率。
class Adder extends Thread
Object o = new Object();
Adder(Object o)
this.o = o;
@Override
public void run()
synchronized (o)
for (long i = 0; i < 100_0000_0000L; i++)
ThreadDemo.n++;
class Suber extends Thread
Object o = new Object();
Suber(Object o)
this.o = o;
@Override
public void run()
synchronized (o)
for (long i = 0; i < 100_0000_0000L; i++)
ThreadDemo.n--;
public class ThreadDemo
static int n = 0;
public static void main(String[] args) throws InterruptedException
Object o = new Object();
Thread a = new Adder(o);
Thread b = new Suber(o);
a.start();
b.start();
a.join();
b.join();
System.out.println(n);
当线程A在操作访问锁定的对象时候, 线程B如果要进入synchronized代码块执行的时候是必须等待锁释放的。这样实际上就是将原本并行执行的代码,变为串行执行了。
sychronized能保护什么,起到什么作用
- 原子性
- 内存可见性(sychronized加锁成功之后,必须做一次从主内存到工作内存得同步操作,保证线程看到的是最新的数据。释放锁之后,必须做一次从工作内存到主内存的刷新操作,保证所有最新的数据写回主内存。用了该关键字也不能保证一定会有同步操作)
- 代码有序性
加锁前的一些语句A
加锁部分的一些语句B
加锁后的一些语句C
创建一个线程安全的ArrayList
单线程下不建议使用Vector,因为Vector无脑给所有方法都加锁了,单线程下会有很多加锁和释放锁的操作来耗费时间。
public class ArrayList
private int size;
private final long[]array = new long[100];
public synchronized void add(long e)
array[size++] = e;
public synchronized int size()
return size;
public synchronized long get(int index)
if (index > 0 || index >= size)
throw new ArrayIndexOutOfBoundsException();
return array[index];
以上是关于一定要会的synchronized关键字的用法的主要内容,如果未能解决你的问题,请参考以下文章
测试人一定要会的技能:selenium的三种等待方式解读,清晰明了