Lock

在jdk1.5中新增了ReentrantLock实现同步,并且在扩展上也更加强大,比如有嗅探锁定、多路分支通知等功能。在使用上比synchronized更加的灵活。

调用ReentrantLock对象的lock方法获得锁,调用unlock方法释放锁。

package me.mymilkbottles.Study08;

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

/**
 * Created by Administrator on 2017/07/16 20:51.
 */
public class ReentrantLockStudy {
    public static void main(String[] args) {
        for (int i = 0;i < 10; ++i) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        MyReentrantLock.doSome();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
}

class MyReentrantLock {
    private static Lock lock = new ReentrantLock();
    public static void doSome() throws InterruptedException {
        lock.lock();
        System.out.println(Thread.currentThread().getName() + " : enter doSome");
        Thread.sleep(2000);
        System.out.println(Thread.currentThread().getName() + " : exit doSome");
        lock.unlock();
    }
}

调用了lock.lock方法的线程就持有了“对象监视器”,其它线程只有等待锁被释放时再次争抢。

ReentrantLock类借助于Condition对象可以实现多路通知功能,可以实现“选择性通知”,在线程调度上比wait、notify更加灵活。

synchronized相当于整个lock对象中只由单一的Condition对象,所有的线程都注册在它一个对象上。线程开始notifyAll时,需要通知所有的WAITING线程,没有选择权,会出现相当大的效率问题。

package me.mymilkbottles.Study08;

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

/**
 * Created by Administrator on 2017/07/16 21:43.
 */
public class Await {
    public static void main(String[] args) {
        Service service = new Service();
        new MyThread(service).start();
        service.doSome();
        System.out.println("end main");
    }
}

class MyThread extends Thread {
    private Service service;
    public MyThread(Service service) {
        this.service = service;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("main signal");
        service.lock.lock();
        service.condition.signal();
        service.lock.unlock();
    }

}
class Service {
    public Lock lock = new ReentrantLock();

    public Condition condition = lock.newCondition();

    public void doSome() {
        lock.lock();
        System.out.println("start doSome");
        try {
            condition.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("end doSome");
        lock.unlock();
    }
}

在使用condition.await()方法调用之前调用lock.lock方法获得同步监视器。

object的wait方法相当于condition类中的await方法。

object类中的wait(long timeout)方法相当于condition类中的signal()方法。

object类中的notify()方法相当于condition类中的signal()方法。

object类中的notifyAll()方法相当于condition类中的signalAll()方法。

使用多个condition实现通知部分线程:

package me.mymilkbottles.Study08;

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

/**
 * Created by Administrator on 2017/07/16 23:19.
 */
public class SignalSome {
    public static void main(String[] args) {
        final Lock lock = new ReentrantLock();
        final Condition conditionA = lock.newCondition();
        final Condition conditionB = lock.newCondition();
        final Condition conditionC = lock.newCondition();
        final Service2[] service2s = new Service2[5];

        for (int i = 0;i < 5; ++i) {
            final int finalI = i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    service2s[finalI] = new Service2(lock, conditionA, conditionB, conditionC);

                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            service2s[finalI].awaitA();
                        }
                    }).start();

                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            service2s[finalI].awaitB();
                        }
                    }).start();

                    new Thread(new Runnable() {
                        @Override
                        public void run() {
                            service2s[finalI].awaitC();
                        }
                    }).start();

                }
            }).start();
        }

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

        for (int i = 0;i < 5; ++i) {
            service2s[i].signalB();
        }
    }
}

class Service2 {

    public Lock lock;

    public Condition conditionA;

    public Condition conditionB;

    public Condition conditionC;

    public Service2(Lock lock, Condition conditionA, Condition conditionB, Condition conditionC) {
        this.lock = lock;
        this.conditionA = conditionA;
        this.conditionB = conditionB;
        this.conditionC = conditionC;
    }

    public void awaitA() {
        lock.lock();
        System.out.println("start await A" + " " + System.currentTimeMillis());
        try {
            conditionA.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("end await A" + " " + System.currentTimeMillis());
        lock.unlock();
    }

    public void awaitB() {
        lock.lock();
        System.out.println("start await B" + " " + System.currentTimeMillis());
        try {
            conditionB.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("end await B" + " " + System.currentTimeMillis());
        lock.unlock();
    }


    public void awaitC() {
        lock.lock();
        System.out.println("start await C" + " " + System.currentTimeMillis());
        try {
            conditionC.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("end await C" + " " + System.currentTimeMillis());
        lock.unlock();
    }

    public void signalA() {
        lock.lock();
        System.out.println("start signal A" + " " + System.currentTimeMillis());
        conditionA.signalAll();
        System.out.println("end signal A");
        lock.unlock();
    }

    public void signalB() {
        lock.lock();
        System.out.println("start signal B" + " " + System.currentTimeMillis());
        conditionB.signalAll();
        System.out.println("end signal B" + " " + System.currentTimeMillis());
        lock.unlock();
    }

    public void signalC() {
        lock.lock();
        System.out.println("start signal C" + " " + System.currentTimeMillis());
        conditionC.signalAll();
        System.out.println("end signal C" + " " + System.currentTimeMillis());
        lock.unlock();
    }

}

实现消费者生产者模式

1、使用两个condition,分别是conditionBlack和conditionWhite进行通知。

package me.mymilkbottles.Study08;

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

/**
 * Created by Administrator on 2017/07/16 23:52.
 */
public class LockConditionPC {
    public static void main(String[] args) {
        final Lock lock = new ReentrantLock();
        final Condition conditionBlack = lock.newCondition();
        final Condition conditionWhite = lock.newCondition();

        for (int i = 0; i < 3; ++i) {

            new Thread(new Runnable() {
                @Override
                public void run() {
                    Print print = new Print(lock, conditionBlack, conditionWhite);
                    while (true) {
                        try {
                            print.printBlack();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();

            new Thread(new Runnable() {
                @Override
                public void run() {
                    Print print = new Print(lock, conditionBlack, conditionWhite);
                    while (true) {
                        try {
                            print.printWhite();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        }
    }
}

class ValueObject {
    public static boolean isLastPrintBlack = false;
}

class Print {
    private Lock lock;
    private Condition conditionBlack;
    private Condition conditionWhite;

    public Print(Lock lock, Condition conditionA, Condition conditionB) {
        this.lock = lock;
        this.conditionBlack = conditionA;
        this.conditionWhite = conditionB;
    }

    public void printBlack() throws InterruptedException {
        lock.lock();
        while (ValueObject.isLastPrintBlack) {
            conditionBlack.await();
        }
        Thread.sleep(1000);
        System.out.println("★");
        ValueObject.isLastPrintBlack = true;
        conditionWhite.signalAll();
        lock.unlock();
    }

    public void printWhite() throws InterruptedException {
        lock.lock();
        while (!ValueObject.isLastPrintBlack) {
            conditionWhite.await();
        }
        Thread.sleep(1000);
        System.out.println("☆");
        ValueObject.isLastPrintBlack = false;
        conditionBlack.signalAll();
        lock.unlock();
    }
}

2、使用一个condition

package me.mymilkbottles.Study08;

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

/**
 * Created by Administrator on 2017/07/17 0:15.
 */
public class LockConditionPCOne {
    public static void main(String[] args) {
        final Lock lock = new ReentrantLock();
        final Condition condition = lock.newCondition();

        for (int i = 0; i < 3; ++i) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Print1 print1 = new Print1(lock, condition);
                    while (true) {
                        try {
                            print1.printBlack();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();

            new Thread(new Runnable() {
                @Override
                public void run() {
                    Print1 print1 = new Print1(lock, condition);
                    while (true) {
                        try {
                            print1.printWhite();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }).start();
        }
    }
}

class ValueObject1 {
    public static boolean isLastPrintBlack = false;
}

class Print1 {
    private Lock lock;
    private Condition condition;

    public Print1(Lock lock, Condition condition) {
        this.lock = lock;
        this.condition = condition;
    }

    public void printBlack() throws InterruptedException {
        lock.lock();
        while (ValueObject1.isLastPrintBlack) {
            condition.await();
        }
        Thread.sleep(1000);
        System.out.println("★");
        ValueObject1.isLastPrintBlack = true;
        condition.signalAll();
        lock.unlock();
    }

    public void printWhite() throws InterruptedException {
        lock.lock();
        while (!ValueObject1.isLastPrintBlack) {
            condition.await();
        }
        Thread.sleep(1000);
        System.out.println("☆");
        ValueObject1.isLastPrintBlack = false;
        condition.signalAll();
        lock.unlock();
    }
}

锁Lock分为公平锁和非公平锁,公平锁表示线程获取锁的顺序是按照线程加锁的顺序来分配的,即先来先得的FIFO先进先出顺序。而非公平锁就是一种获取锁的抢占机制,是随机获得锁的,和公平锁不一样的就是先来的不一定先得到锁。

使用ReentrantReadWriteLock类

类ReentrantLock具有完全互斥排他的效果,即同一时间只由一个线程在执行ReentrantLock.lock方法后面的任务。这样做虽然保证了实例变量的线程安全性,但是效率是非常低下的,所以jdk提供了一种读写锁ReentrantReadWriteLock类,使用它可以加快运行效率,在某些不需要操作实际变量的方法中,完全可以使用读写锁来提升该方法的代码运行速度。

读写锁表示也有两个锁,一个是读操作相关的锁,也称为共享锁。另一个是写操作相关的锁,也叫排他锁。多个读锁之间不互斥,读锁和写锁互斥,写锁和写锁互斥。

多个Thread可以同时进行读取操作,但是同一时刻只允许一个Thread进行写入操作。

package me.mymilkbottles.Study09;

import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * Created by Administrator on 2017/07/17 13:02.
 */
public class ReentrantReadWriteLockStudy {
    public static void main(String[] args) {
        final ReentrantReadWriteLock readLock = new ReentrantReadWriteLock();
        final ReentrantReadWriteLock wirteLock = new ReentrantReadWriteLock();
        for (int i = 0; i < 3; ++i) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Service3 service3 = new Service3();
                    service3.lock = readLock;
                    service3.doSome();
                }
            }).start();

            new Thread(new Runnable() {
                @Override
                public void run() {
                    Service3 service3 = new Service3();
                    service3.lock1 = wirteLock;
                    service3.doSome1();
                }
            }).start();
        }
    }
}

class Service3 {
    public ReentrantReadWriteLock lock;

    public ReentrantReadWriteLock lock1;

    public void doSome() {
        try {
            lock.readLock().lock();
            System.out.println("start read " + System.currentTimeMillis());
            Thread.sleep(2000);
            System.out.println("end read " + System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.readLock().unlock();
        }
    }

    public void doSome1() {
        try {
            lock1.writeLock().lock();
            System.out.println("start write " + System.currentTimeMillis());
            Thread.sleep(2000);
            System.out.println("end write " + System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock1.writeLock().unlock();
        }
    }

}

上面的例子可以体现出:读读共享、写写互斥。

package me.mymilkbottles.Study09;

import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * Created by Administrator on 2017/07/17 13:15.
 */
public class ReadWriteMutex {
    public static void main(String[] args) {
        final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
        for (int i = 0; i < 5; ++i) {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    Service4 service4 = new Service4();
                    service4.lock = lock;
                    service4.doSomeRead();
                }
            }).start();

            new Thread(new Runnable() {
                @Override
                public void run() {
                    Service4 service4 = new Service4();
                    service4.lock = lock;
                    service4.doSomeWrite();
                }
            }).start();
        }
    }
}

class Service4 {
    public ReentrantReadWriteLock lock;

    public void doSomeWrite() {
        try {
            lock.writeLock().lock();
            System.out.println("start do some write " + System.currentTimeMillis());
            Thread.sleep(2000);
            System.out.println("end do some write " + System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.writeLock().unlock();
        }
    }

    public void doSomeRead() {
        try {
            lock.readLock().lock();
            System.out.println("start do some read " + System.currentTimeMillis());
            Thread.sleep(2000);
            System.out.println("end do some read " + System.currentTimeMillis());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.readLock().unlock();
        }
    }
}
/*
执行结果:
start do some read 1500268840498
end do some read 1500268842499
start do some write 1500268842499
end do some write 1500268844499
start do some write 1500268844499
end do some write 1500268846499
start do some write 1500268846499
end do some write 1500268848499
start do some write 1500268848499
end do some write 1500268850499
start do some write 1500268850499
end do some write 1500268852500
start do some read 1500268852500
start do some read 1500268852500
start do some read 1500268852500
start do some read 1500268852500
end do some read 1500268854500
end do some read 1500268854500
end do some read 1500268854500
end do some read 1500268854500
*/

上面的例子可以体现:读写互斥

你可能感兴趣的:(java多线程,并发)