1.Java多线程中的竞争条件概念
Java中的多线程,当多个线程对一个数据进行操作时,可能会产生“竞争条件”的现象,这时候需要对线程的操作进行加锁,来解决多线程操作一个数据时可能产生问题。加锁方式有两种,一个是申明Lock对象来对语句快进行加锁,另一种是通过synchronized 关键字来对方法进行加锁。以上两种方法都可以有效解决Java多线程中存在的竞争条件的问题。
2.wait(),notify(),notifyAll()
首先,调用一个Object的wait与notify/notifyAll的时候,必须保证调用代码对该Object是同步的,也就是说必须在作用等同于synchronized(obj){......}的内部才能够去调用obj的wait与notify/notifyAll三个方法,否则就会报错
- wait()
调用任意对象的 wait() 方法导致该线程阻塞,该线程不可继续执行,并且该对象上的锁被释放。wait()总是在一个循环中被调用,挂起当前线程来等待一个条件的成立。 Wait调用会一直等到其他线程调用notifyAll()时才返回。 - notify()
调用任意对象的notify()方法则导致因调用该对象的 wait()方法而阻塞的线程中随机选择的一个解除阻塞(但要等到获得锁后才真正可执行)。 - 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 代理对象的生成。
网友评论