java多线程,每个线程会有独立的内存,会先从主内存中复制一份到独立内存,cpu中的寄存器都会是独立线程内存。
如果线程太忙,就不会从主内存中同步值,会导致数据不一致读不到。
public class Test2 {
int n = 1;
Object o = new Object();
public static void main(String[] args) {
Test2 t = new Test2();
Thread th1 = new Thread(t::aa);
Thread th2 = new Thread(t::bb);
th1.start();
th2.start();
}
public void aa() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "修改开始");
n = 2;
System.out.println(Thread.currentThread().getName() + "修改结束");
}
public void bb() {
while (true) {
if (n == 2) {//由于这个线程读的很快,线程没有空余时间去同步n的数据 ,如果有System.out.print或者sleep或synchronized就会同步
System.out.println("结束");
break;
}
}
}
}
结果
Thread-0修改开始
Thread-0修改结束
解决方法是
volatile int n = 1;
这样每次读取n都会去同步一下主内存值。
synchronized锁都是锁堆的。
volatile只能做到读取最新的,并不能保证原子性,适合一个线程修改参数当开关使用,性能要号,能用volatile就不用synchronized
多个线程修改某个数值还是要用synchronized
wait,notify,notifyall都必须在synchronized里
wait会释放锁,然后自身线程进入等待状态。
notify会叫醒synchronized锁住对象中的wait线程,但是不会释放锁,即使叫醒,醒来的线程没有得到锁也不能继续执行
o.notify();
try {
o.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
叫醒后 再wait自己释放锁。
叫醒的线程执行完后再o.notify()
这样就比较麻烦,但是好理解。
package com.github.pig.auth;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public class Test {
private volatile int count = 0;
private List<Integer> list = new ArrayList<>();
AtomicInteger acout = new AtomicInteger(0);
Object o = new Object();
Object o2 = new Object();
boolean b = true;
Thread t1;
Thread t2;
public static void main(String[] args) {
Test t = new Test();
t.t1 = new Thread(t::aa);
t.t2 = new Thread(t::bb);
t.t2.start();
t.t1.start();
}
CountDownLatch latch = new CountDownLatch(1);//门闩1个
public void aa() {
for (int i = 0; i < 10; i++) {
count++;
list.add(count);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (list.size() == 5) {
// o.notify();
// try {
// o.wait();
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
latch.countDown();//开一个门闩
}
System.out.println("t1:" + count);
}
}
public void bb() {
if (list.size() != 5) {
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
// System.out.println(count);
// try {
// o.wait();
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
System.out.println("到5");
}
// o.notify();
}
}
t1:1
t1:2
t1:3
t1:4
t1:5
到5
t1:6
t1:7
t1:8
t1:9
t1:10
Process finished with exit code 0