java线程和锁机制总结(一)

目录

Thread 和 Runnable的区别

在实际开发中多使用实现Runnable接口原因

锁介绍

Synchronized同步关键词

lock和synchronized区别

ReentrantReadWriteLock和ReentrantLock区别


 

Runnable 和Thread区别

  1. Runnable 是接口,Thread 是类,且实现了Runnable接口。
  2. Runnable定义的子类中没有start方法,只有在Thread类类中有。
  3. Thread类中只有一个构造方法,public Thread(Runnable targer),该构造方法接受Runnable的所有子类的实例,可以通过Thread类来启动runnable来实现多线程。

 

在实际开发中多使用实现Runnable接口原因

  1. 因为与继承Thread类相比,很好的解决了java中只能单继承的限制,通过接口来实现继承。
  2. runnbal实现资源共享,而Thraed类中每个线程独立不共享。
  3. 实现Runnable接口实现了资源共享,出现乱序使用同步关键词(synchronized)
  4. 但是如果使用synchronized时,一个线程出现了阻塞,但是又没有释放锁,线程只能等待,影响效率。
  5. 通过Lock锁机制来使多个线程实现读写操作,解决线程之间发生冲突。ReadWriteLock是一个接口,在它里面只定义了两个方法:一个读的锁和一个写的锁。读的锁:A线程获取了读的锁,那么B线程也可以获取读的锁。写的锁:A线程获取了写的锁,那么B线程不能获取读也不能获取写的锁。(具体内容见下文介绍)
public class MyThreadWithImplements implements Runnable {

    private int tickets = 10;

    @Override
    public synchronized void run() {

        for (int i = 0; i <= 100; i++) {
            if(tickets>0){
                System.out.println(Thread.currentThread().getName()+"--卖出票:" + tickets--);
            }
        }
    }


    public static void main(String[] args) {

        MyThreadWithImplements myRunnable = new MyThreadWithImplements();
        Thread thread1 = new Thread(myRunnable, "窗口一");
        Thread thread2 = new Thread(myRunnable, "窗口二");
        Thread thread3 = new Thread(myRunnable, "窗口三");

        thread1.start();
        thread2.start();
        thread3.start();
    }

 

锁介绍

1、可重入锁(ReenTrant)

        像synchronized和 ReentrantLock都是可重入锁,可重入性在我看来实际上表明了锁的分配机制:基于线程的分配,而不是基于方法调用的分配。 

2、可中断锁 

        synchronized不是可中断锁,Lock是可中断锁。

3、公平锁 

        ①公平锁即尽量以请求锁的顺序来获取锁。比如同是有多个线程在等待一个锁,当这个锁被释放时,等待时间最久的线程(最先请求的线程)会获得该所,这种就是公平锁。非公平锁即无法保证锁的获取是按照请求锁的顺序进行的。这样就可能导致某个或者一些线程永远获取不到锁。

        ②synchronized就是非公平锁,它无法保证等待的线程获取锁的顺序。

        ③ReentrantLock和ReentrantReadWriteLock,它默认情况下是非公平锁,但是可以设置为公平锁。

             ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);     

4、读写锁  

        synchronized读锁和读锁互斥, ReentrantReadWriteLock为读和读为共享锁

 

Synchronized同步关键词

        一个代码块被synchronized修饰了,当一个线程获取了对应的锁,并执行该代码块时,其他线程便只能一直等待,等待获取锁的线程释放锁。这种特性又被称为互斥锁

而这里获取锁的线程释放锁只会有两种情况:

  1. 获取锁的线程执行完了该代码块,然后线程释放对锁的占有。
  2. 线程执行发生异常,此时JVM会让线程自动释放锁。

 

lock和synchronized区别

  1. Lock不是Java语言内置的,synchronized是Java语言的关键字,因此是内置特性。Lock是一个类,通过这个类可以实现同步访问;
  2. Lock和synchronized有一点非常大的不同,采用synchronized不需要用户去手动释放锁,当synchronized方法或者synchronized代码块执行完之后,系统会自动让线程释放对锁的占用;而Lock则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。
  3. Lock可以让等待锁的线程响应中断,而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;
  4. 通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。
  5. Lock可以提高多个线程进行读操作的效率。

 

ReentrantReadWriteLock和ReentrantLock区别

       ReentrantReadWriteLock是Lock的另一种实现方式,我们已经知道了ReentrantLock是一个排他锁,同一时间只允许一个线程访问,而ReentrantReadWriteLock允许多个读线程同时访问,但不允许写线程和读线程、写线程和写线程同时访问。相对于排他锁,提高了并发性。在实际应用中,大部分情况下对共享数据(如缓存)的访问都是读操作远多于写操作,这时ReentrantReadWriteLock能够提供比排他锁更好的并发性和吞吐量。

     读写锁内部维护了两个锁,一个用于读操作,一个用于写操作。所有 ReadWriteLock实现都必须保证 writeLock操作的内存同步效果也要保持与相关 readLock的联系。也就是说,成功获取读锁的线程会看到写入锁之前版本所做的所有更新。

  ReentrantReadWriteLock支持以下功能:

  1. 支持公平和非公平的获取锁的方式;
  2. 支持可重入。读线程在获取了读锁后还可以获取读锁;写线程在获取了写锁之后既可以再次获取写锁又可以获取读锁;
  3. 还允许从写入锁降级为读取锁,其实现方式是:先获取写入锁,然后获取读取锁,最后释放写入锁。但是,从读取锁升级到写入锁是不允许的;
  4. 读取锁和写入锁都支持锁获取期间的中断;
  5. Condition支持。仅写入锁提供了一个 Conditon 实现;读取锁不支持 Conditon ,readLock().newCondition() 会抛出 UnsupportedOperationException。 
public class LearnDemo
{
    private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();


    public static void main (String[] args){

        final LearnDemo userRrw  = new LearnDemo();

        new Thread(new Runnable(){
            @Override
            public void run() {
                userRrw.get(Thread.currentThread());
                userRrw.write(Thread.currentThread());
            }
        }).start();

    }

    public void get(Thread thread){
        reentrantReadWriteLock.readLock().lock();
        try{
            long start = System.currentTimeMillis();
            System.out.println("start = "+start);
            while(System.currentTimeMillis()-start<=1){
                System.out.println("System.currentTimeMillis() = "+start);
                System.out.println(thread.getName()+"执行读操作");
            }
            System.out.println(thread.getName()+"读操作执行完毕");
        }catch(Exception e){
            e.printStackTrace();
        }finally {
            reentrantReadWriteLock.readLock().unlock();
        }
    }
    public void write(Thread thread){
        reentrantReadWriteLock.writeLock().lock();
        try{
            Long start = System.currentTimeMillis();
            while(System.currentTimeMillis()-start<=1){
                System.out.println(thread.getName()+"执行写操作");
            }
            System.out.println(thread.getName()+"写操作执行完毕");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            reentrantReadWriteLock.writeLock().unlock();
        }
    }
}

参考文章:https://blog.csdn.net/zengmingen/article/details/53217229

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值