java多线程

java多线程锁总结

java线程锁

公平锁/非公平锁
公平锁:多个线程按照申请锁的顺序来获取锁。(先来后到原则)
非公平锁: 多个线程按照获取锁的顺序并不是按照申请锁的顺序。有可能后申请的线程先获取锁。在高并发的情况下,有可能会造成优先级反转或有饥饿现象(较公平锁的有点:吞吐量比公平锁大)

Lock lock = new ReentrantLock(); //构造方法无参则默认false 即 非公平锁
Lock lock = new ReentrantLock(boolean fair);//传参 true 即公平锁

可重入锁(递归锁)
线程可以进入任何一个它已经拥有锁所同步着的代码块(套娃模式)
作用:可避免死锁发生

package com.springboot.atguigu.demo;

import ch.qos.logback.core.util.TimeUtil;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;


/**
 * 可重用锁(递归锁)
 */
class Phone implements Runnable{
    public synchronized void sendSMS(){
        System.out.println(Thread.currentThread().getName()+"\t sendSMS()");
        sendEmail();
    }

    public synchronized void sendEmail(){
        System.out.println(Thread.currentThread().getName()+"\t sendEmail()");
    }

    //===================
    Lock lock = new ReentrantLock(); //公平锁


    @Override
    public void run() {
        get();
    }
    
	/**
	* 小知识点 当加多把锁时 编译及运行不会报错
	* 当锁和解锁不对应时 会死锁
	*/
    public void get(){
        lock.lock();
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName()+"\t get()");
            set();
        }finally {
            lock.unlock();
            lock.unlock();
        }
    }

    public void set(){
        lock.lock();
        try {
            System.out.println(Thread.currentThread().getName()+"\t set()");

        }finally {
            lock.unlock();
        }
    }
}

public class ReenterLockDemo {

    public static void main(String[] args) {
    Phone phone = new Phone();

       new Thread(new Runnable() {
           @Override
           public void run() {

               phone.sendSMS();
           }
       },"t1").start();



       new Thread(new Runnable() {
           @Override
           public void run() {
               phone.sendSMS();
           }
       },"t2").start();


        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println();
        System.out.println();
        System.out.println();
        System.out.println();


        Thread t3 = new Thread(phone);
       Thread t4 = new Thread(phone);

       t3.start();
       t4.start();
    }
}

运行结果:
在这里插入图片描述控制台一直处于运行状态

自旋锁
指尝试获取锁的线程不会立即阻塞,而是采用循环的方式去尝试获取锁,这样的好处时减少线程上下文切换的消耗,缺点时循环会消耗CPU

手写自旋锁会是一道面试题尽量多手写几遍让自己会写!!!
总结:自旋锁时通过CAS(compareAndSet 比较并交换)实现 CPU并发原语
CAS:判断内存某个位置的值是否为预期值,如果时则更新为新值,过程原子。
原语的执行必须是连续的,在执行过程过不允许被打断,CAS是一条CPU的原语指令,不会造成所谓的数据不一致问题。

package com.springboot.atguigu.demo;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 自旋锁
 */
public class SpinLockDemo {

    static AtomicReference<Thread> reference = new AtomicReference<>();

    public static void mylock(){
        Thread thread = Thread.currentThread();
        System.out.println(Thread.currentThread().getName()+"\t" + "come in");
        while (!reference.compareAndSet(null,thread)){

        }
    }

    public static void MyUnlock(){
        Thread thread = Thread.currentThread(); // bu
        reference.compareAndSet(thread, null);
        System.out.println(Thread.currentThread().getName()+"\t" + " invoked MyUnlock...");
    }

    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                mylock();
                try {
                    TimeUnit.SECONDS.sleep(5);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                MyUnlock();
            }
        },"AA").start();

        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        new Thread(new Runnable() {
            @Override
            public void run() {
                mylock();
                MyUnlock();
            }
        },"BB").start();

    }

}

读写锁
独占锁(写锁)共享锁(读锁)互斥锁
独占锁:指该锁一次只能被一个线程所持有。对ReenTrantLock和Synchronized都是独占锁
共享锁:该锁可被多个线程所持有。对ReentantReadWriteLock其读锁是共享锁,写是独占锁
读锁的共享锁可保证并发读是高效的,读写、写写 、写读过程互斥是互斥锁

package com.springboot.atguigu.demo;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantReadWriteLock;

class MyCache{
    private volatile Map<String,Object> map = new HashMap<>();
    private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();

    public void put(String key,Object value){

        rwLock.writeLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "\t 正在写入" + key);
            try {
                TimeUnit.MILLISECONDS.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            map.put(key, value);
            System.out.println(Thread.currentThread().getName() + "\t 写入完成");
        }finally {
            rwLock.writeLock().unlock();
        }

    }

    public void get(String key){



        rwLock.readLock().lock();
        try {
            System.out.println(Thread.currentThread().getName() + "\t 正在读取");

            try {
                TimeUnit.SECONDS.sleep(300);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            Object o = map.get(key);
            System.out.println(Thread.currentThread().getName() + "\t 读取完成" + o);
        }finally {
            rwLock.readLock().unlock();
        }

    }

}

/**
 *  读-读 能共存
 *  读-写 不能共存
 *  写-写 不能共存
 *
 *  写操作:原子+ 独占 整个过程必须是一个完成的统一体,中间不允许被分割 被打断。
 */
public class ReadWriteLockDemo {

    public static void main(String[] args) {
        MyCache myCache = new MyCache();
        for (int i = 0; i <= 5 ; i++) {
            int finalI = i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    myCache.put(finalI + "",finalI);
                }
            },i + "").start();

        }


        for (int i = 0; i <= 5 ; i++) {
            int finalI = i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    myCache.get(finalI + "");
                }
            },i + "").start();

        }



    }
}

第一次写文章。。。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值