• 129136

    文章

  • 809

    评论

  • 12

    友链

  • 最近新加了换肤功能,大家多来逛逛吧~~~~
  • 喜欢这个网站的朋友可以加一下QQ群,我们一起交流技术。

Java线程总结---第二天

服了这份高薪指南,涨多少你说了算>>

wait和notify

wait

方法 wait() 的作用是使当前执行代码的线程进行等待,该方法会将该线程放 入”预执行队列“中,并且在wait()所在的代码处停止执行,直到接到通知或被中断为止。

在调用 wait() 之前,线程必须获得该对象级别锁,这是一个很重要的地方, 很多时候我们可能会忘记这一点,即只能在同步方法或同步块中调用 wait() 方法

还需要注意的是 wait() 是释放锁的,即在执行到 wait() 方法之后,当前线 程会释放锁,当从 wait() 方法返回前,线程与其他线程竞争重新获得锁。

notify

和 wait() 方法一样, notify() 方法也要在同步块或同步方法中调用,即在调用前,线程也必须获得该对象的对象级别锁。

该方法是用来通知那些可能等待该对象的对象锁的其他线程,如果有多个线程等 待,则由线程规划器随机挑选出其中一个呈wait状态的线程,对其发出通知notify,并使它等待获取该对象的对象锁。

这里需要注意的是,执行notify方法之后,当前线程不会立即释放其拥有的该对 象锁,而是执行完之后才会释放该对象锁,被通知的线程也不会立即获得对象锁,而 是等待notify方法执行完之后,释放了该对象锁,才可以获得该对象锁。

notifyAll() 通知所有等待同一共享资源的全部线程从等待状态退出,进入可 运行状态,重新竞争获得对象锁。

小程序demo


public class MyList {

    private List list = new ArrayList();

    public void add() {
        list.add("new word");
    }

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

public class ThreadA extends Thread {

    private MyList myList;

    public ThreadA(MyList myList) {
        super();
        this.myList = myList;
    }

    @Override
    public void run() {
        try {
            for (int i=0;i<10;i++){
                synchronized (myList){
                    myList.add();
                    if (myList.size()==5){
                        myList.notify();
                        System.out.println("发出size为5的通知");
                    }
                    System.out.println("添加了" + (i + 1) + "个元素!");
                    Thread.sleep(1000);
                }
            }
        }catch (InterruptedException ex){
            ex.printStackTrace();
        }


    }
}

public class ThreadB extends Thread {

    private MyList myList;

    public ThreadB(MyList myList) {
        super();
        this.myList = myList;
    }

    @Override
    public void run() {
        try {
            synchronized (myList){
                if (myList.size() !=5){
                    System.out.println("wait begin " +
                            System.currentTimeMillis());
                    myList.wait();
                    System.out.println("wait end " +
                            System.currentTimeMillis());
                }
            }
        }catch (InterruptedException ex){
            ex.printStackTrace();
        }

    }
}

使用wait/notify模拟BlockingQueue阻塞队列

BlockingQueue是阻塞队列,我们需要实现的是阻塞的放入和得到数据,设计思路如 下:

初始化队列最大长度为5;

需要新加入的时候,判断是否长度为5,如果是5则等待插入;

需要消费元素的时候,判断是否为0,如果是0则等待消费;

程序如下:

import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @program: demo
 * @description:
 * @author: lee
 * @create: 2019-02-26
 **/
public class MyBlockQueue {

    //设计一个承载元素的列表
    private final LinkedList<Object> linkedList = new LinkedList<Object>();
    //设计一个计数器
    private final AtomicInteger atomicInteger = new AtomicInteger(0);

    private final int maxSize = 5;

    private final int minSize = 0;

    //初始化锁对象
    private final Object ob = new Object();

    public void put(Object object) {
        synchronized (ob) {
            if (atomicInteger.get() == maxSize) {
                try {
                    ob.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            linkedList.add(object);
            atomicInteger.getAndIncrement();
            System.out.println("元素 " + object + " 被添加 ");
            ob.notify(); //通知另外一个阻塞的线程方法
        }
    }

    public Object get() {
        Object temp;
        synchronized (ob) {
            //达到最小,没有元素无法消费,进入等到
            while (atomicInteger.get() == minSize) {
                try {
                    ob.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            atomicInteger.getAndDecrement();
            temp = linkedList.removeFirst();
            System.out.println("元素" + temp + "被消费");
            ob.notify();
        }
        return temp;
    }

    private int size() {
        return atomicInteger.get();
    }


    public static void main(String[] args) throws InterruptedException {
        final MyBlockQueue myBlockQueue = new MyBlockQueue();
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 1000; i++) {
                    myBlockQueue.put(i);
                }
            }
        }, "thread1").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    for (int i = 0; ; i++) {
                        myBlockQueue.get();
                        Thread.sleep(1000);
                    }
                } catch (InterruptedException ex) {
                    ex.printStackTrace();
                }

            }
        }, "thread2").start();
    }
}

ReentrantLock实现线程之间的同步

小程序

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

/**
 * @program: demo
 * @description:
 * @author: lee
 * @create: 2019-02-26
 **/
public class ReentrantLockDemo {

    public static void main(String[] args) {
        Lock lock=new ReentrantLock();
        new Thread(new Runnable() {
            @Override
            public void run() {
                runMethod(lock,1000);
            }
        },"thread1").start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                runMethod(lock,1000);
            }
        },"thread2").start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                runMethod(lock,1000);
            }
        },"thread3").start();
    }

    private static void runMethod(Lock lock,long sleepTime){
        lock.lock();
        try {
            Thread.sleep(sleepTime);
            System.out.println("ThreadName:" + Thread.currentThread().getName());

        }catch (InterruptedException ex){
            ex.printStackTrace();
        }finally {
            lock.unlock();
        }

    }
}    

用Lock对象和多Condition实现等待/通知实例

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

/**
 * @program: demo
 * @description:
 * @author: lee
 * @create: 2019-02-26
 **/
public class ReentrantLockDemo {
    private Lock lock=new ReentrantLock();
    private Condition condition1=lock.newCondition();
    private Condition condition2=lock.newCondition();

    private void await(Condition condition){
        try {
            lock.lock();
            System.out.println("开始等待await! ThreadName: "+Thread.currentThread().getName());
            condition.await();
            System.out.println("等待await结束! ThreadName: "+Thread.currentThread().getName()   );
        }catch (InterruptedException ex){
            ex.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    private void signal(Condition condition){
        lock.lock();
        System.out.println("发送通知signal!  ThreadName: "+Thread.currentThread().getName());
        condition.signal();
        lock.unlock();
    }
    public static void main(String[] args) {
        ReentrantLockDemo reentrantLockDemo=new ReentrantLockDemo();

        new Thread(new Runnable() {
            @Override
            public void run() {
                reentrantLockDemo.await(reentrantLockDemo.condition1);
            }
        },"thread1").start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                reentrantLockDemo.signal(reentrantLockDemo.condition1);
            }
        },"thread2").start();
        new Thread(new Runnable() {
            @Override
            public void run() {

                reentrantLockDemo.await(reentrantLockDemo.condition2);
            }
        },"thread3").start();

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

                reentrantLockDemo.signal(reentrantLockDemo.condition2);
            }
        },"thread3").start();
    }

}

程序是有小bug的,隐藏的bug是程序很可能一直处于等待唤醒状态,这是因为线程的执行顺序是未知的原因造成的。

公平锁和非公平锁

概念很好理解,公平锁表示线程获取锁的顺序是按照线程加锁的顺序来分配,即先进先出,那么他就是公平的;非公平是一种抢占机制,是随机获得锁,并不是先来的一定能先得到锁,结果就是不公平。

ReentrantLock提供了一个构造方法,可以很简单的实现公平锁或非公平锁,源代码构 造函数如下:

    /**
     * Creates an instance of {@code ReentrantLock} with the
     * given fairness policy.
     *
     * @param fair {@code true} if this lock should use a fair ordering policy
     */
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

上面的代码修改为公平锁实现方式,不会出现一直等待的状态

 private Lock lock=new ReentrantLock(true);
  

ReentrantLock常用其他方法

getHoldCount()方法:查询当前线程保持此锁定的个数,也就是调用lock()的次 数;

getQueueLength()方法:返回正等待获取此锁定的线程估计数目;

isFair()方法:判断是不是公平锁。

ReentrantReadWriteLock实现并发

ReentrantReadWriteLock有两个锁:一个是与读相关的锁,称为“共享锁”;另一个是与写相关的锁,称为“排它锁”。也就是多个读锁之间不互斥,读锁与写锁互斥,写锁与写锁互斥。

ReentrantReadWriteLock锁的特性

读读共享;

写写互斥;

读写互斥;

写读互斥;

读读共享

import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @program: demo
 * @description:
 * @author: lee
 * @create: 2019-02-26
 **/
public class Demo {
    private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();

    public static void main(String[] args) {
        Demo demo=new Demo();
        new Thread(new Runnable() {
            @Override
            public void run() {
                demo.read();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                demo.read();
            }
        }).start();

        
    }
    private void read(){
        try {
            reentrantReadWriteLock.readLock().lock();
            System.out.println("目前正在执行的线程是----->"+Thread.currentThread().getName());
            Thread.sleep(1000);
            System.out.println("目前执行结束的线程是----->"+Thread.currentThread().getName());

        }catch (InterruptedException ex){
            ex.printStackTrace();
        }finally {
            reentrantReadWriteLock.readLock().unlock();
        }
    }
}

执行结果

目前正在执行的线程是----->Thread-0
目前正在执行的线程是----->Thread-1
目前执行结束的线程是----->Thread-0
目前执行结束的线程是----->Thread-1

写写互斥

import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @program: demo
 * @description:
 * @author: lee
 * @create: 2019-02-26
 **/
public class Demo {
    private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();

    public static void main(String[] args) {
        Demo demo=new Demo();

        new Thread(new Runnable() {
            @Override
            public void run() {
                demo.write();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                demo.write();
            }
        }).start();
    }
    private void read(){
        try {
            reentrantReadWriteLock.readLock().lock();
            System.out.println("目前正在执行读的线程是----->"+Thread.currentThread().getName());
            Thread.sleep(1000);
            System.out.println("目前执行结束的读线程是----->"+Thread.currentThread().getName());

        }catch (InterruptedException ex){
            ex.printStackTrace();
        }finally {
            reentrantReadWriteLock.readLock().unlock();
        }
    }

    private void write(){
        try {
            reentrantReadWriteLock.writeLock().lock();
            System.out.println("目前正在执行的写线程是----->"+Thread.currentThread().getName());
            Thread.sleep(1000);
            System.out.println("目前执行结束的写线程是----->"+Thread.currentThread().getName());

        }catch (InterruptedException ex){
            ex.printStackTrace();
        }finally {
            reentrantReadWriteLock.writeLock().unlock();
        }
    }
}

读写互斥或写读互斥

import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @program: demo
 * @description:
 * @author: lee
 * @create: 2019-02-26
 **/
public class Demo {
    private ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();

    public static void main(String[] args) {
        Demo demo=new Demo();
        new Thread(new Runnable() {
            @Override
            public void run() {
                demo.read();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                demo.read();
            }
        }).start();
        
        new Thread(new Runnable() {
            @Override
            public void run() {
                demo.write();
            }
        }).start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                demo.write();
            }
        }).start();
    }
    private void read(){
        try {
            reentrantReadWriteLock.readLock().lock();
            System.out.println("目前正在执行读的线程是----->"+Thread.currentThread().getName());
            Thread.sleep(1000);
            System.out.println("目前执行结束的读线程是----->"+Thread.currentThread().getName());

        }catch (InterruptedException ex){
            ex.printStackTrace();
        }finally {
            reentrantReadWriteLock.readLock().unlock();
        }
    }

    private void write(){
        try {
            reentrantReadWriteLock.writeLock().lock();
            System.out.println("目前正在执行的写线程是----->"+Thread.currentThread().getName());
            Thread.sleep(5000);
            System.out.println("目前执行结束的写线程是----->"+Thread.currentThread().getName());

        }catch (InterruptedException ex){
            ex.printStackTrace();
        }finally {
            reentrantReadWriteLock.writeLock().unlock();
        }
    }
}

输出结果

目前正在执行读的线程是----->Thread-0
目前正在执行读的线程是----->Thread-1
目前执行结束的读线程是----->Thread-0
目前执行结束的读线程是----->Thread-1
目前正在执行的写线程是----->Thread-2
目前执行结束的写线程是----->Thread-2
目前正在执行的写线程是----->Thread-3
目前执行结束的写线程是----->Thread-3

695856371Web网页设计师②群 | 喜欢本站的朋友可以收藏本站,或者加入我们大家一起来交流技术!

0条评论

Loading...


发表评论

电子邮件地址不会被公开。 必填项已用*标注

自定义皮肤 主体内容背景
打开支付宝扫码付款购买视频教程
遇到问题联系客服QQ:419400980
注册梁钟霖个人博客