概念:
是利用锁的机制来实现同步的.
锁机制有如下两种特性:
互斥性: 即在同一时间只允许一个线程持有某个对象锁, 通过这种特性来实现多线程中的协调机制, 这样在同一时间只有一个线程对需同步的代码块 (复合操作) 进行访问. 互斥性我们也往往称为操作的原子性.
可见性: 必须确保在锁被释放之前, 对共享变量所做的修改, 对于随后获得该锁的另一个线程是可见的(即在获得锁时应获得最新共享变量的值), 否则另一个线程可能是在本地缓存的某个副本上继续操作从而引起不一致.
为什么要使用 synchronized:
在并发编程中存在线程安全问题, 主要原因有:
1. 存在共享数据
2. 多线程共同操作共享数据.
synchronized 的作用:
关键字 synchronized 可以保证在同一时刻, 只有一个线程可以执行某个方法或某个代码块, 同时 synchronized 可以保证一个线程的变化可见(可见性), 即可以代替 volatile.
synchronized 的用法:
1. 普通同步方法(实例方法), 锁是当前实例对象 , 进入同步代码前要获得当前实例的锁
- public class synchronizedTest implements Runnable {
- static synchronizedTest instance=new synchronizedTest();
- static int i=0;
- @Override
- public void run() {
- // 省略其他耗时操作....
- // 使用同步代码块对变量 i 进行同步操作, 锁对象为 instance
- synchronized(instance){
- for(int j=0;j<10000;j++){
- i++;
- }
- }
- }
- public static void main(String[] args) throws InterruptedException {
- Thread t1=new Thread(instance);
- Thread t2=new Thread(instance);
- t1.start();
- t2.start();
- t1.join();
- t2.join();
- System.out.println(i);
- }
- }
2. 静态同步方法, 锁是当前类的 class 对象 , 进入同步代码前要获得当前类对象的锁
(1) 同步非静态方法
- // 修饰非静态方法
- // 代码块 1(对象)this 指的是当前对象
- public void accessResources1(){
- synchronized(this){
- try {
- synchronized (this){
- TimeUnit.MINUTES.sleep(2);
- }
- System.out.println(Thread.currentThread().getName()+"is runing");
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- // 代码块 1(CLASS 类)
- public void accessResources4(){
- synchronized(SynchroDemo01.class){//ClassLoader class ---》堆 Class 所有的对象
- // 有 Class 对象的所有的对象都共同使用这一个锁
- try {
- TimeUnit.SECONDS.sleep(2);
- System.out.println(Thread.currentThread().getName()+"is runing");
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- public static void main(String[] args) {
- final SynchroDemo01 deno01=new SynchroDemo01();
- for (int i = 0; i < 5; i++) {
- new Thread(deno01::accessResources1).start();
- }
- }
(2) 同步静态方法
- public class synchronizedTest implements Runnable {
- // 共享资源
- static int i =0;
- /**
- * synchronized 修饰实例方法
- */
- public static synchronized void increase(){
- i++;
- }
- @Override
- public void run(){
- for (int j =0 ; j<10000;j++){
- increase();
- }
- }
- public static void main(String[] args) throws InterruptedException {
- Thread t1 = new Thread(new synchronizedTest());
- Thread t2 = new Thread(new synchronizedTest());
- t1.start();
- t2.start();
- t1.join();
- t2.join();
- System.out.println(i);
- }
根据获取的锁分类:
synchronized 从锁的是谁的维度一共有两种情况:
锁住类
锁住对象实例
1)静态方法上的锁
静态方法是属于 "类", 不属于某个实例, 是所有对象实例所共享的方法. 也就是说如果在静态方法上加入 synchronized, 那么它获取的就是这个类的锁, 锁住的就是这个类.
2)实例方法 (普通方法) 上的锁
实例方法并不是类所独有的, 每个对象实例独立拥有它, 它并不被对象实例所共享. 这也比较能推出, 在实例方法上加入 synchronized, 那么它获取的就是这个累的锁, 锁住的就是这个对象实例.
那锁住类还是锁住对象实例,
来源: http://www.bubuko.com/infodetail-3393513.html