synchronized、DCL、volatile、死锁

前言

多线程和高并发专题
系统编程(多任务)
什么是多任务
操作系统如何实现多任务
1.时间片切换
2.优先级别调度

java是如何实现多任务 – 多线程
java如何实现多线程的方法:
1.继承Thread
2.实现Runable接口
3.实现CallabeFuture接口(1.5提供的)
4.jdk提供了线程池用来获取线程(1.5)
线程安全问题:
加锁
1.synchronized关键字的使用
2. Lock锁

正文

(一)synchronized关键字

同步锁:
有三种写法

1、放在方法上:整个方法都是同步 如果某个方法中所有代码,都有可能出现线程安全问题,建议将synchronized直接写在方法上面,如果将synchronized写在方法上面,该方法就是锁。如下代码示例:

public class TestThread implements Runnable {
    private int count = 0;

    @Override
    public synchronized void run() {
        for (int i = 0; i < 1000000; i++) {
                count++;
            }
        }
        System.out.println("结果是:"+ count);
    }

2、同步块:将有可能出现线程安全的代码放在一个同步块中key就是一个对象,什么对象都可以,一般建议使用this关键字充当synchronized (key) { // 可能出现线程安全问题放在这里面 count++;} 如下代码示例:

public class TestThread implements Runnable {
    private int count = 0;

    @Override
    public void run() {
        for (int i = 0; i < 1000000; i++) {
        synchronizedthis{
       			count++;
        		}
       	 	}
        }
        System.out.println("结果是:"+ count);
    }

3、静态方法:比较特殊,单独说该静态方法加synchronized关键字,因为静态方法属于,所以该类(本质就是该类的字节码文件)在充当锁。如下代码示例:

public class TestThread implements Runnable {
    private int count = 0;

    @Override
    public void run() {
        for (int i = 0; i < 1000000; i++) {
	        synchronizedTestThread.class{
	       		count++;
        	}
       	}
       	System.out.println("结果是:"+ count);
    }
}

最后补充一下关于synchronize:
synchronized锁的锁升级问题
jdk7.0 synchronized进行了打的改动:
synchronized直接向操作系统申请锁,资源的消耗太大了,太重了。
Oracle进行了改造:

1、无锁状态(偏向锁)
2、锁就会从偏向锁升级到自旋锁(CAS)CAS(compare and swap):比较并且交换自旋锁很容易引起:ABA问题 。
3、自旋锁升级为重量级锁

(二)DCL(double check lock)

双重锁
1.懒汉式,单例设计模式中的写法!!
2.要注意,指令重排序问题!!!

懒汉式:
1.在需要使用对象的时候,再去创建对象,解决掉了饿汉式的内存占有问题。
2.懒汉式是无法直接使用的多线程中,因为是非线程安全的.

如果要解决线程安全问题,需要加锁处理:
1.直接在方法上面加锁,直接解决掉了线程安全,但是效率不高(锁的范围太大)
2.在创建对象的代码上加锁(锁的范围小,效率高)<======如果这种写法,需要两次判断非空

public class Single2 {
	//volatitle
    // 1、起到了内存可见性;2、禁止指令重排序
    private static volatile Single2 single = null;

    // 私有化构造函数
    private Single2() {}

    // 懒汉式
    public static Single2 getInstance() {
        if (single == null) {
            synchronized (Single.class) {
                if (single == null) {
                    single = new Single2();
                }
            }
        }
        return single;
    }
}

(三)volatile

volatile关键字:
高并发可见性有序性原子性

多线程情况下,每一个线程都独立拥有一个执行栈,每一个线程都是独立有用数据的,彼此之间是内存不可见的。
在java中,volatile关键字有两大核心作用:
1、被它修饰的变量,在多线程中,可以打破内存屏障,也就是说被它修饰的变量,就有可见性的。(每一次数据变化,每个线程都是知道的)
2、禁止指令重排序!!!

public class TestThread03 {
    public static void main(String[] args) throws InterruptedException {
        MyThread03 mt = new MyThread03();
        mt.start();
        Thread.sleep(3000);
        mt.flag = true;
        System.out.println("此时count ="+ mt.count);
    }
}

class MyThread03 extends Thread {
    public int count;
    // volatile 关键字,让变量可见性
    public volatile boolean flag;
    
    @Override
    public void run() {
        // 程序并没有被终止
       while (!flag) {
            count++;
       }
    }
}

(四)死锁(dead lock)

多线程情况下,线程安全问题,通过加锁来解决问题。

死锁现象:一定要避免!!!造成大量的资料浪费,同时有解决不了问题。
避免死锁:一种比较优秀的解决方案:银行家算法

形成死锁有四个必要条件:

1.互斥
2.请求保持
3.环路等待
4.不可剥夺条件

死锁是一种资源的浪费,在正常的编程中,一定要避免死锁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值