synchronized:内部锁

synchronized:内部锁

起源: 并行程序开发涉及多线程、多任务间的协作和数据共享

一)、内部锁:synchronized

1).定义在方法上

public synchronized void method()

当method方法被调用时,调用线程必须获得当前对象的锁。

锁对象:当前对象。

2).同步代码块

synchronized(Object obj){ }

锁对象:自定义一个共同使用的锁对象。

好处:

1.同步块可以更为精确的控制同步代码范围

2.小的代码块非常有利于锁的快进快出,假设同步块前后代码段较为耗时,而它

​ 们又无需进行同步操作,那么,将这些代码纳入整个同步代码块就会增加锁的等

​ 待时间。

3).静态方法的同步

public synchronized static method()

锁对象:Class对象

4).使用wait()、notify()来创建一个阻塞队列

构建:

方法一:当队列有数据时,取出第一个元素,没有数据时,线程进入等待状态,线

​ 程被阻塞。

方法二:将一个对象添加进入队列,并通知等待的方法。

使用wait()、notify()实现了多线程之间的协作以及数据的共享。

模拟队列:

/**
 * 使用synchronize和wait(), notify()实现一个阻塞队列
 * 实现:
 *    获取队列中的元素: 使用pop操作队列,当队列中有元素,则取出第一个元素,若队列为空,线程进入等待状态
 *    使用put()方法添加元素,并唤醒等待的线程
 */
public class BlockQueue {
    List list = new ArrayList<>();
    public synchronized Object pop() throws InterruptedException {
        //当涉及条件判断时,wait方法要在一个循环中使用,并指出跳出循环的条件
        //原因:若使用if语句,线程被唤醒,直接执行接下的业务逻辑,不再进行list.size() == 0的判断,若之前队列的
        //元素被消费,此时又再次唤醒该线程,队列中无数据,执行业务逻辑出错。
        //将wait()放入while中,唤醒线程后会再次进行条件判断,条件满足则执行业务逻辑。
        if(list.size() == 0) {
            this.wait();
        }
        if(list.size() > 0){
            System.out.println("取值");
            return list.remove(0);
        }else{
            return null;
        }
    }

    public synchronized void put(Object obj){
        list.add(obj);
        this.notify();
    }
}

测试:

public class ThreadPoolTest {
    public static void main(String[] args) {
        BlockQueue queue = new BlockQueue();
        //两个线程,一个线程获取队列的数据,如果队列有数据则获取数据,如果没有则等待
        /**
         *  使用线程池来创建线程对象
         */
        ExecutorService executor = Executors.newFixedThreadPool(10);
        //线程一,取数据
        executor.execute(new Runnable(){
            @Override
            public void run(){
                while(true) {
                    //获取队列的数据
                    try {
                        queue.pop();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        executor.execute(new PopThread(queue));
        //线程二,放数据
        executor.execute( new Runnable(){
            @Override
            public void run(){
                while(true) {
                   String a = "1";
                    queue.put(a);
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }


}

猜你喜欢

转载自www.cnblogs.com/Auge/p/11759944.html