挂面10

2019-11-05  本文已影响0人  盼旺

1.Java多线程中的竞争条件概念

Java中的多线程,当多个线程对一个数据进行操作时,可能会产生“竞争条件”的现象,这时候需要对线程的操作进行加锁,来解决多线程操作一个数据时可能产生问题。加锁方式有两种,一个是申明Lock对象来对语句快进行加锁,另一种是通过synchronized 关键字来对方法进行加锁。以上两种方法都可以有效解决Java多线程中存在的竞争条件的问题。

2.wait(),notify(),notifyAll()

首先,调用一个Object的wait与notify/notifyAll的时候,必须保证调用代码对该Object是同步的,也就是说必须在作用等同于synchronized(obj){......}的内部才能够去调用obj的wait与notify/notifyAll三个方法,否则就会报错

5.谈一下synchronized和wait()、notify()等的关系

1.有synchronized的地方不一定有wait,notify
2.有wait,notify的地方必有synchronized.这是因为wait和notify不是属于线程类,而是每一个对象都具有的方法,而且,这两个方法都和对象锁有关,有锁的地方,必有synchronized。
3.如果要把notify和wait方法放在一起用的话,必须先调用notify后调用wait,因为如果调用完wait,该线程就已经不是当前线程了。所以它得先提醒别人我准备释放锁了

4.Java实现阻塞队列

public class BlockingQueue {
    private List queue = new LinkedList();
    private int limit = 10;
    public BlockingQueue(int limit){
        this.limit=limit;
    }
    public  synchronized void enqueue(Object item) throws InterruptedException{
        while (this.queue.size()==this.limit){
            wait();
        }
        if(this.queue.size()==0){
            notifyAll();
        }
        this.queue.add(item);
    }
    public synchronized Object dequeue() throws InterruptedException{
        while (this.queue.size()==0){
            wait();
        }
        if(this.queue.size()==this.limit){
            notifyAll();
        }
        return this.queue.remove(0);
    }
}

在enqueue和dequeue方法内部,只有队列的大小等于上限(limit)或者下限(0)时,才调用notifyAll方法。如果队列的大小既不等于上限,也不等于下限,任何线程调用enqueue或者dequeue方法时,都不会阻塞,都能够正常的往队列中添加或者移除元素。

5.Java 多线程中两个线程交替执行,一个输出偶数,一个输出奇数

java8方法引用有四种形式:
静态方法引用       :   ClassName :: staticMethodName
构造器引用        :   ClassName :: new
类的任意对象的实例方法引用:   ClassName :: instanceMethodName
特定对象的实例方法引用  :   object :: instanceMethodName

1.利用synchronized  notify() wait()
public class ThreadPrintDemo2 {
    public static void main(String[] args) {
        final ThreadPrintDemo2 demo2 = new ThreadPrintDemo2();
        Thread t1 = new Thread(demo2::print1);
        Thread t2 = new Thread(demo2::print2);

        t1.start();
        t2.start();
    }

    public synchronized void print2() {
        for (int i = 1; i <= 100; i += 2) {
            System.out.println(i);
            this.notify();//先提醒别人,我准备释放锁了
            try {
                this.wait();
                Thread.sleep(100);// 防止打印速度过快导致混乱
            } catch (InterruptedException e) {
                // NO
            }
        }
    }

    public synchronized void print1() {
        for (int i = 0; i <= 100; i += 2) {
            System.out.println(i);
            this.notify();
            try {
                this.wait();
                Thread.sleep(100);// 防止打印速度过快导致混乱
            } catch (InterruptedException e) {
                // NO
            }
        }
    }
}

使用 volatile

public class ThreadPrintDemo2 {
    static volatile int num = 0;
    static volatile boolean flag = false;
    public static void main(String[] args) {
        Thread t1 = new Thread(() -> {
            for (; num<100; ) {
                if (!flag && (num == 0 || num % 2 == 0)) {
                    num++;
                    try {
                        Thread.sleep(100);// 防止打印速度过快导致混乱
                    } catch (InterruptedException e) {
                        //NO
                    }

                    System.out.println(num);
                    flag = true;
                }
            }
        }
        );

        Thread t2 = new Thread(() -> {
            for (; num<100;) {
                if (flag && (num% 2 != 0)) {
                    num++;
                    try {
                        Thread.sleep(100);// 防止打印速度过快导致混乱
                    } catch (InterruptedException e) {
                        //NO
                    }

                    System.out.println(num);
                    flag = false;
                }
            }
        }
        );
        t1.start();
        t2.start();
    }
}
num++ 不是原子的,但不妨碍,因为有 flag 变量控制。
而 num 必须是 volatile 的,如果不是,会导致可见性问题。

6.java中什么叫原子操作?

就是无法被别的线程打断的操作。要么不执行,要么就执行成功。
例如:
x=3是原子操作。过程就是先把工作内存的x赋成3,再把主存的x赋成3。
y=x不是原 子操作,它涉及在工作内存先把x值读出来,再把这个值赋给y。
x++x=x+1也不是原子操作,它涉及取值,自加和赋值。

7.mybatis的接口和xml交互,用到了代理了吗?

用到了JAVA动态代理
注册:将 Mapper.xml 中的节点信息和 Mapper 类中的注解信息与 Mapper 类的方法一一对应,每个方法对应生成一个 MapperStatement,并添加到 Configuration 中;
绑定:根据 Mapper.xml 中的 namespace 生成一个 Mapper.class 对象,并与一个 MapperProxyFactory 代理工厂对应,用于 Mapper 代理对象的生成。

上一篇 下一篇

猜你喜欢

热点阅读