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

来源:互联网 发布:小米生态链产品 知乎 编辑:程序博客网 时间:2024/06/03 23:38

浅谈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();    }}
阅读全文
0 0