线程高级篇-Synchronized锁,Lock锁区别和Condition线程并行

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/pang_da_xing/article/details/78008962

浅谈Synchronized:

synchronized是Java的一个关键字,也就是Java语言内置的特性,如果一个代码块被synchronized修饰了,当一个线程获取了对应的锁,执行代码块时,其他线程
便只能一直等待,等待获取锁的线程释放锁,而获取锁的线程释放锁会有三种情况:
1).获取锁的线程执行完该代码块,然后线程释放对锁的占有;
2).线程执行发生异常,此时JVM会让线程自动释放锁;
3).调用wait方法,在等待的时候立即释放锁,方便其他的线程使用锁.

Lock的特性:

1).Lock不是Java语言内置的;
2).synchronized是在JVM层面上实现的,如果代码执行出现异常,JVM会自动释放锁,但是Lock不行,要保证锁一定会被释放,就必须将unLock放到finally{}中(手动释放);
3).在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetarntLock,但是在很激烈的情况下,synchronized的性能会下降几十倍;
4).ReentrantLock增加了锁:
a. void lock(); // 无条件的锁;
b. void lockInterruptibly throws InterruptedException;//可中断的锁;
解释:  使用ReentrantLock如果获取了锁立即返回,如果没有获取锁,当前线程处于休眠状态,直到获得锁或者当前线程可以被别的线程中断去做其他的事情;但是如果是synchronized的话,如果没有获取到锁,则会一直等待下去;
c. boolean tryLock();//如果获取了锁立即返回true,如果别的线程正持有,立即返回false,不会等待;
d. boolean tryLock(long timeout,TimeUnit unit);//如果获取了锁立即返回true,如果别的线程正持有锁,会等待参数给的时间,在等待的过程中,如果获取锁,则返回true,如果等待超时,返回false;
5)Lock的ReentrantReadWriteLock读写锁 适用于 读多写少的场景 效率较高

Condition的特性:

1.Condition中的await()方法相当于Object的wait()方法,Condition中的signal()方法相当于Object的notify()方法,Condition中的signalAll()相当于Object的notifyAll()方法。不同的是,Object中的这些方法是和同步锁捆绑使用的;而Condition是需要与互斥锁/共享锁捆绑使用的。
2.Condition它更强大的地方在于:能够更加精细的控制多线程的休眠与唤醒。对于同一个锁,我们可以创建多个Condition,在不同的情况下使用不同的Condition。
    例如,假如多线程读/写同一个缓冲区:当向缓冲区中写入数据之后,唤醒”读线程”;当从缓冲区读出数据之后,唤醒”写线程”;并且当缓冲区满的时候,”写线程”需要等待;当缓冲区为空时,”读线程”需要等待。
如果采用Object类中的wait(), notify(), notifyAll()实现该缓冲区,当向缓冲区写入数据之后需要唤醒”读线程”时,不可能通过notify()或notifyAll()明确的指定唤醒”读线程”,而只能通过notifyAll唤醒所有线程(但是notifyAll无法区分唤醒的线程是读线程,还是写线程)。 但是,通过Condition,就能明确的指定唤醒读线程。

实例

ListAdd.java 使用synchronized

package ThreadCollections;


import java.util.ArrayList;
import java.util.List;

/**
 * Created by 胖大星 on 2017/9/12.
 */
public class ListAdd {
   private volatile static  List list = new ArrayList();

   public void addList(){
       list.add("hello");
   }

   public int size(){
       return list.size();
   }

   public static void main(String[] agrs){
       final ListAdd list1 = new ListAdd();
       Object lock = new Object();
       Thread thread = new Thread(new Runnable(){
           @Override
           public void run() {
                   try {
                       synchronized (lock){
                           for (int i = 0; i < 10; i++) {
                               list1.addList();
                               System.out.println("当前线程为: "+Thread.currentThread().getName()+"  "+i);
                               Thread.sleep(500);
                               if(list.size() == 5){
                                   System.out.println("当前通知已发出!");
                                   lock.notify();
                               }
                           }
                       }
                   }
                   catch (InterruptedException e){
                        e.printStackTrace();
                   }
           }
       },"t1");

       Thread thread2 = new Thread(new Runnable() {
           @Override
           public void run() {
               synchronized (lock) {
                   if (list1.size() != 5) {
                       try {
                            lock.wait();
                       } catch (InterruptedException e) {
                           e.printStackTrace();
                       }
                   }
                   System.out.println("当前线程:" + Thread.currentThread().getName()+"已经收到通知");
                   throw new RuntimeException();
               }
           }
       },"t2");

       thread2.start();
       thread.start();

   }
}

UseReentrantLock.java 使用Lock

package Lock;

import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by 胖大星 on 2017/9/17.
 * Lock 比 synchronized 方法更加便捷,灵活
 */
public class UseReentrantLock {
    //new ReentrantLock(false) 可以带参数 false 表示非公平锁(根据cpu分配优先执行) true表示公平锁(先来先执行)
    private ReentrantLock lock = new ReentrantLock();
    public void method1(){
        try {
            lock.lock();
            System.out.println("当前线程:"+Thread.currentThread().getName()+"进入method1...");
            Thread.sleep(1000);
            System.out.println("当前线程:"+Thread.currentThread().getName()+"退出method1...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }
    public void method2(){
        try {
            lock.lock();
            System.out.println("当前线程:"+Thread.currentThread().getName()+"进入method2...");
            Thread.sleep(1000);
            System.out.println("当前线程:"+Thread.currentThread().getName()+"退出method2...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        UseReentrantLock useReentrantLock = new UseReentrantLock();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                useReentrantLock.method1();
                useReentrantLock.method2();
            }
        }, "t1");

        t1.start();
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

UseManyCondition.java 使用多个Condition

package Lock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
 * Created by 胖大星 on 2017/9/17.
 *启动多个 Condition 并行锁  同时并行多个线程
 */
public class UseManyCondition {

    private ReentrantLock lock = new ReentrantLock();
    private Condition c1 = lock.newCondition();
    private Condition c2 = lock.newCondition();

    public void m1(){
        try {
            lock.lock();
            System.out.println("当前线程:" +Thread.currentThread().getName() + "进入方法m1等待..");
            c1.await();
            System.out.println("当前线程:" +Thread.currentThread().getName() + "方法m1继续..");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void m2(){
        try {
            lock.lock();
            System.out.println("当前线程:" +Thread.currentThread().getName() + "进入方法m2等待..");
            c1.await();
            System.out.println("当前线程:" +Thread.currentThread().getName() + "方法m2继续..");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void m3(){
        try {
            lock.lock();
            System.out.println("当前线程:" +Thread.currentThread().getName() + "进入方法m3等待..");
            c2.await();
            System.out.println("当前线程:" +Thread.currentThread().getName() + "方法m3继续..");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void m4(){
        try {
            lock.lock();
            System.out.println("当前线程:" +Thread.currentThread().getName() + "唤醒..");
            c1.signalAll();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void m5(){
        try {
            lock.lock();
            System.out.println("当前线程:" +Thread.currentThread().getName() + "唤醒..");
            c2.signal();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {


        final UseManyCondition umc = new UseManyCondition();
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                umc.m1();
            }
        },"t1");
        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                umc.m2();
            }
        },"t2");
        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                umc.m3();
            }
        },"t3");
        Thread t4 = new Thread(new Runnable() {
            @Override
            public void run() {
                umc.m4();
            }
        },"t4");
        Thread t5 = new Thread(new Runnable() {
            @Override
            public void run() {
                umc.m5();
            }
        },"t5");

        t1.start(); // c1
        t2.start(); // c1
        t3.start(); // c2


        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        t4.start(); // c1
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        t5.start(); // c2

    }



}

UseReentrantReadWriteLock.java Lock使用读写锁

package Lock;

import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * Created by 胖大星 on 2017/9/17.
 * lock的ReentrantReadWriteLock读写锁  适用于 读多写少的场景 效率较高
 */
public class UseReentrantReadWriteLock {
    private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();
    private ReentrantReadWriteLock.ReadLock readLock = reentrantReadWriteLock.readLock();
    private ReentrantReadWriteLock.WriteLock writeLock = reentrantReadWriteLock.writeLock();

    public void read(){
        try {
            readLock.lock();
            System.out.println("当前线程:"+Thread.currentThread().getName()+"进入....");
            Thread.sleep(3000);
            System.out.println("当前线程:"+Thread.currentThread().getName()+"退出....");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            readLock.unlock();
        }
    }

    public void write(){
        try {
            writeLock.lock();
            System.out.println("当前线程:"+Thread.currentThread().getName()+"进入....");
            Thread.sleep(3000);
            System.out.println("当前线程:"+Thread.currentThread().getName()+"退出....");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            writeLock.unlock();
        }
    }

    public static void main(String[] args) {
        UseReentrantReadWriteLock useReentrantReadWriteLock = new UseReentrantReadWriteLock();
        Thread threadRead1 = new Thread(new Runnable() {
            @Override
            public void run() {
                useReentrantReadWriteLock.read();
            }
        }, "threadRead1");
      Thread threadRead2 = new Thread(new Runnable() {
                @Override
                public void run() {
                    useReentrantReadWriteLock.read();
                }
            }, "threadRead2");

        Thread threadWrite1 = new Thread(new Runnable() {
            @Override
            public void run() {
                useReentrantReadWriteLock.write();
            }
        }, "threafWrite1");

        Thread threadWrite2 = new Thread(new Runnable() {
            @Override
            public void run() {
                useReentrantReadWriteLock.write();
            }
        }, "threafWrite2");

        //两个读线程同时开始 ,写线程明显较慢
        threadRead1.start();
       // threadRead2.start();
        threadWrite1.start();
      //  threadWrite2.start();
    }
}

猜你喜欢

转载自blog.csdn.net/pang_da_xing/article/details/78008962