第九章 Java多线程与并发原理(复习)

一、互斥锁的特性
1、互斥性(原子性)
只有一个线程持有对象锁。
2、可见性
对共享变量的修改对之后的线程可见。
二、锁的分类
1、对象锁
2、类锁
三、获取的方法
1、synchronized(){
}//同步代码快
2、public synchronized void method(){
}//同步方法
四、两种方法的区别
1、一个线程调用同步方法或这同步代码块另一个不调用,两者互不影响。

public class SynchronizedTest {
    public synchronized void methodA(){
        try{
            for (int i=0;i<5;i++){
                System.out.println("methodA-"+i);
                Thread.sleep(1000);
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
     /**
     * 同步代码快
     */
    public void methodA(){
        synchronized (this){
            try{
                for (int i=0;i<5;i++){
                    System.out.println("methodA-"+i);
                    Thread.sleep(1000);
                }
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
    public void methodB(){
        try{
            for (int i=0;i<5;i++){
                System.out.println("methodB-"+i);
                Thread.sleep(1000);
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }

    }

    public static void main(String[] args) {
        SynchronizedTest test=new SynchronizedTest();
        Thread thread1=new Thread(new Runnable() {
            @Override
            public void run() {
                test.methodA();
            }
        });
        thread1.start();
        Thread thread2=new Thread(new Runnable() {
            @Override
            public void run() {
                test.methodB();
            }
        });
        thread2.start();
    }
}

结果
methodA-0
methodB-0
methodA-1
methodB-1
methodB-2
methodA-2
methodB-3
methodA-3
methodB-4
methodA-4
2、synchronization与synchronization(this)都是在this对象上上锁,所以会堵塞,如果synchronization(所属类不同)则不会堵塞。

public class SynchronizedTest {
    public synchronized void methodA2(){
        try{
            for (int i=0;i<5;i++){
                System.out.println("methodA2-"+i);
                Thread.sleep(1000);
            }
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    /**
     * 同步代码快
     */
    public void methodA(){
        synchronized (this){
            try{
                for (int i=0;i<5;i++){
                    System.out.println("methodA-"+i);
                    Thread.sleep(1000);
                }
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }

//    public void methodB(){
//        try{
//            for (int i=0;i<5;i++){
//                System.out.println("methodB-"+i);
//                Thread.sleep(1000);
//            }
//        }catch (InterruptedException e){
//            e.printStackTrace();
//        }
//
//    }
    public void methodB(){
        Object obj=new Object();
        synchronized (obj){
            try{
                for (int i=0;i<5;i++){
                    System.out.println("methodB-"+i);
                    Thread.sleep(1000);
                }
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        SynchronizedTest test=new SynchronizedTest();
        Thread thread1=new Thread(new Runnable() {
            @Override
            public void run() {
                test.methodA();
            }
        });
        thread1.start();
        Thread thread2=new Thread(new Runnable() {
            @Override
            public void run() {
                test.methodB();
            }
        });
        thread2.start();
    }
}

结果
methodB-0
methodA-0
methodA-1
methodB-1
methodA-2
methodB-2
methodA-3
methodB-3
methodA-4
methodB-4
A2被堵塞
同步代码块与同步方法的区别
同步代码块会在开头插入monitorenter在结尾插入monitorexit指令,用于获取monitor。
同步方法是通过JVM检查ACC_SYNCHRONIZED获取。
五、synchronized的四种状态
1、无锁
2、偏向锁
markword记录着锁的Id当线程再次获取锁的时候只需比较ThreadID即可。
缺点:不适用于锁竞争的情况
3、轻量级锁
对象头中的lock record用于存储markword的拷贝
拷贝成功后markword的指针指向lockrecord
markword标志位职位00
在这里插入图片描述
4、重量级锁
总结
在这里插入图片描述

ReentrantLock再入锁
一、性质
1、位于java.util.concurrent.locks中
2、基于AQS实现
3、比synchronization更细粒度
4、可重入的公平锁
5、lock()后一定要释放锁

public class ReentrantLockDeom implements Runnable{
//    private static ReentrantLock lock=new ReentrantLock(false);非公平锁
private static ReentrantLock lock=new ReentrantLock(true);
    @Override
    public void run() {
        while (true){
            try {
                lock.lock();
                System.out.println(Thread.currentThread().getName()+"got lock");
                Thread.sleep(1000);
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                lock.unlock();//一定要关锁
            }

        }

    }

    public static void main(String[] args) {
        ReentrantLockDeom rtld=new ReentrantLockDeom();
        Thread thread1=new Thread(rtld);
        Thread thread2=new Thread(rtld);
        thread1.start();
        thread2.start();
    }
}

结果
非公平锁
Thread-0got lock
Thread-0got lock
Thread-0got lock
Thread-0got lock
Thread-0got lock
Thread-0got lock
Thread-0got lock
线程分配不公平
公平锁
Thread-1got lock
Thread-0got lock
Thread-1got lock
Thread-0got lock
Thread-1got lock
线程分配公平
二、ReentrantLock公平性设置
1、参数为ture是倾向于把锁赋予等待时间最久的线程
2、公平锁获取锁的顺序为lock方法的顺序
三、ReentrantLick将锁对象化
1、判断是否有线程,或者某个特定的线程在排队等待获取锁。
2、带超时的获取锁的尝试

public class ReenyrantLockTest {
    static Lock lock1 = new ReentrantLock();
    static Lock lock2 = new ReentrantLock();

    public static void main(String[] args) {
        Thread thread = new Thread(new ThreadDemo(lock1, lock2));//该线程先获取锁1,再获取锁2
        Thread thread1 = new Thread(new ThreadDemo(lock2, lock1));//该线程先获取锁2,再获取锁1
        thread.start();
        thread1.start();
    }


    static class ThreadDemo implements Runnable {
        Lock firstLock;
        Lock secondLock;

        public ThreadDemo(Lock firstLock, Lock secondLock) {
            this.firstLock = firstLock;
            this.secondLock = secondLock;
        }

        @Override
        public void run() {
            try {
                while (!lock1.tryLock()) {
                    TimeUnit.MILLISECONDS.sleep(10);
                }
                while (!lock2.tryLock()) {
                    lock1.unlock();
                    TimeUnit.MILLISECONDS.sleep(10);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                firstLock.unlock();
                secondLock.unlock();
                System.out.println(Thread.currentThread().getName() + "正常结束!");
            }
        }
    }

}

ReentrantLock还给我们提供了获取锁限时等待的方法tryLock(),可以选择传入时间参数,表示等待指定的时间,无参则表示立即返回锁申请的结果:true表示获取锁成功,false表示获取锁失败。我们可以使用该方法配合失败重试机制来更好的解决死锁问题
3、感知有没有成功获取锁。
4、可以将wait/notify/notifyAll对象化
四、synchronized和ReentrantLock的区别
1、synchronized是关键字,ReentrantLock是类
2、Reentrabtlock可以让等待锁的线程中断,避免死锁。
3、Reentrabtlock可以获取锁的信息知道有没有成功的获取锁。
4、Reentrabtlock可以灵活的实现多路通知
sync操作在markword中,lock调用Unsafe类的park()方法。
5、发生异常的时候synchronization会释放锁避免死锁,Reentrabtlock要释放。
五、什么是java内存模型jmm
是一个抽象的概念,一组规则或规范,通过这组规范定义了程序中各个变量的访问规则。
六、jmm
jmm是围绕原子性,有序性,可见性展开的
七、happens-before八大原则
1、程序次序原则
2、传递原则
3、锁定原则
4、对象终结原则
5、线程启动原则
6、线程中断原则
7、线程终结
8、volitile原则
八、volitile详解
1、volitile是jvm提供的轻量级同步机制,所有线程可见,并且禁止指令重排序优化。
2、volitile变量为何立即可见
因为当写一个volition变量是,jmm会把工作内存中的共享变量刷到主内存中,当读到volition变量是线程对应的工作内存无效。
九、volitile与synchronization的区别
1、volitile的本质是告诉JVM当前变量在工作内存中是不确定的,需要从主内存中读取。
synchronization是锁定当前变量,只有当前线程可以访问该变量,其他线程只能等到该线程完成为止。
2、volitile只能运用于变量级别,synchronization可以用于变量,方法区,类级别。
3、volitile只能保持修改可见性,不能保持原子性。
synchronization可见性,原子性
4、volitile不会造成线程的阻塞,synchronized可能会造成线程的阻塞。
5、volatile标记的变量不会被编译器优化,synchronized可以优化。
十、实现线程安全的单例写法

/**
 * 单例的双重检测实现
 */
public class Singleton {
    private static Singleton instance;
    private Singleton(){ }
    public static Singleton getInstance(){
        //第一次检测
        if (instance==null){
            //同步
            synchronized (Singleton.class){
                if (instance==null){
                    //多线程环境下可能会出现问题的地方
                    instance=new Singleton();
                }
            }
        }
        return instance;
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值