哈!抓住你了!
重点重点重点~
线程安全问题,就是某个代码在多线程环境下执行,会出bug,即线程不安全,即不符合预期~
本质的本质,是因为线程之间的调度顺序是不确定的~
首先我们可以将计数器做成对象,或者用“全局性质”的静态变量~
public class Test {
public static int count = 0;
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
count++;
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
count++;
}
});
thread1.start(); //启动
thread2.start();
thread1.join(); //等线程结束~
thread2.join();
System.out.println(count);
}
}
class Counter {
private int count = 0;
public void add() {
count++;
}
public int get() {
return count;
}
}
public class Test {
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 5000; i++) {
counter.add();
}
});
for (int i = 0; i < 5000; i++) {
counter.add();
}
thread1.start();
thread1.join();
System.out.println(counter.get());
}
}
thread1.start();
System.out.println(counter.get());
thread1.join();
System.out.println(counter.get());
没错,因为只加5000次,main线程一下子就跑完了
你只要加多点,肯定会出错~
不过你较真的话,有百分之0.00000001的可能成功~
其实什么方式,只要次数低点,都很有可能结果正确
count++语句的非原子性
对于一条语句
对于一段语句
那么怎么解决呢?
class Counter {
private int count = 0;
public void add() {
synchronized (this) {
count++;
}
}
public int get() {
return count;
}
}
public class Test1 {
public static int count = 0;
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 50000; i++) {
counter.add();
}
});
for (int i = 0; i < 50000; i++) {
counter.add();
}
thread1.start();
thread1.join();
System.out.println(counter.get());
}
}
Object类作为锁对象时,则代表,进入这个代码块,从始至终,必然需要抢到锁才行,没抢到锁的线程,阻塞等待~
不同于其他方式,这个并没有明确的锁对象
* 是个同步锁
注意:不同锁对象的话,就相当于修改不同变量,并不会引起阻塞,不会锁竞争,那就跟没加锁一样,反而增加了开销
补充说明:
类对象的含义:
类对象相当于“对象的图纸”
类对象还能直接调用静态方法/静态属性
public class Test {
public static int flag;
public static void main(String[] args) {
Thread thread = new Thread(() -> {
while(flag == 0) {
}
System.out.println("thread线程over");
});
Thread thread1 = new Thread(() -> {
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = 1;
});
thread.start();
thread1.start();
}
}
但是实际情况是:
这个也是编译器优化的策略~
如果外加一个线程,此线程判断a是否为null,如果不是,调用a的一个方法~
在这里,我不给代码演示了,因为不好演示,并且错误率不高,但是也不能说没有~
文章到此结束!谢谢观看
可以叫我 小马,我可能写的不好或者有错误,但是一起加油鸭!