思考:
什么是线程安全
不管业务中遇到怎样的多个线程访问某对象或某方法的情况,而在编程这个业务逻辑的时候,都不需要额外做任何额外的处理(也就是可以像单线程编程一样),程序也可以正常运行(不会因为多线程而出错),就可以称为线程安全。
主要是两个问题
运行结果错误:a++ 多线程下出现消失的请求现象
活跃性问题:死锁、活锁、饥饿
对象发布和初始化的时候的安全问题
public class MultiThreadsError implements Runnable {
int index = 0;
static MultiThreadsError instance = new MultiThreadsError();
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(instance);
Thread thread2 = new Thread(instance);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println(instance.index);
}
@Override
public void run() {
for (int i = 0; i < 10000; i++) {
index++;
}
}
}
运行结果错误:没有原子性
思考:
如何找到上一个案例中出错的值
public class MultiThreadsError implements Runnable {
int index = 0;
static MultiThreadsError instance = new MultiThreadsError();
// 原子计数器功能
static AtomicInteger realIndex = new AtomicInteger();
static AtomicInteger wrongIndex = new AtomicInteger();
// 由于线程的执行的先后顺序无法确定,所以加入栅栏,让他们同时出发
static volatile CyclicBarrier cyclicBarrier1 = new CyclicBarrier(2);
// 同时释放
static volatile CyclicBarrier cyclicBarrier2 = new CyclicBarrier(2);
// 使用 boolean 数组标记到错误的值
final boolean[] marked = new boolean[1000000];
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(instance);
Thread thread2 = new Thread(instance);
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("表面上运行结果是 " + instance.index);
System.out.println("真正运行的次数 " + realIndex.get());
System.out.println("错误的次数 " + wrongIndex.get());
}
@Override
public void run() {
marked[0] = true;
for (int i = 0; i < 10000; i++) {
try {
cyclicBarrier1.await(); // 栅栏(当有两个线程执行过它,放行)
} catch (Exception e) {
e.printStackTrace();
}
index++;
try {
cyclicBarrier1.reset();
cyclicBarrier2.await();
} catch (Exception e) {
e.printStackTrace();
}
realIndex.incrementAndGet();
synchronized (instance) {
if (marked[index] && marked[index - 1]) {
System.out.println("发生了错误" + index);
wrongIndex.incrementAndGet();
}
}
marked[index] = true;
}
}
}
public class MultiThreadError implements Runnable {
int flag = 1;
static Object object1 = new Object();
static Object object2 = new Object();
public static void main(String[] args) {
MultiThreadError r1 = new MultiThreadError();
MultiThreadError r2 = new MultiThreadError();
r1.flag = 1;
r2.flag = 0;
new Thread(r1).start();
new Thread(r2).start();
}
@Override
public void run() {
System.out.println("flag = " + flag);
if (flag == 1) {
synchronized (object1) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object2) {
System.out.println("object 1");
}
}
}
if (flag == 0) {
synchronized (object2) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (object1) {
System.out.println("object 2");
}
}
}
}
}
什么是发布
什么是逸出
public class MultiThreadsError3 {
private Map<String, String> states;
public MultiThreadsError3() {
states = new HashMap<>();
states.put("1", "周一");
states.put("2", "周二");
states.put("3", "周三");
states.put("4", "周四");
}
public Map<String, String> getStates() {
return states;
}
public Map<String, String> getStatesImproved() {
return new HashMap<>(states);
}
public static void main(String[] args) {
MultiThreadsError3 multiThreadsError3 = new MultiThreadsError3();
Map<String, String> states = multiThreadsError3.getStates();
System.out.println(states.get("1"));
states.remove("1");
System.out.println(states.get("1"));
}
}
public class MultiThreadsError4 {
static Point point;
public static void main(String[] args) throws InterruptedException {
new PointMaker().start();
Thread.sleep(505);
if (point != null) {
System.out.println(point);
}
}
}
class Point {
private final int x, y;
public Point(int x, int y) throws InterruptedException {
this.x = x;
MultiThreadsError4.point = this;
Thread.sleep(100); // MultiThreadsError4 中会根据 sleep 的大于或小于的阻塞时间而变化
this.y = y;
}
@Override
public String toString() {
return "Point{" +
"x=" + x +
", y=" + y +
'}';
}
}
class PointMaker extends Thread {
@Override
public void run() {
try {
new Point(1, 1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class MultiThreadsError5 {
int count;
public MultiThreadsError5(MySource source) {
source.registerListener(new EventListener() {
@Override
public void onEvent(Event e) {
System.out.println("\n我得到的数字是" + count);
}
});
for (int i = 0; i < 10000; i++) {
System.out.print(i);
}
count = 100;
}
public static void main(String[] args) {
MySource mySource = new MySource();
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
mySource.eventCome(new Event() {
});
}
}).start();
MultiThreadsError5 multiThreadsError5 = new MultiThreadsError5(mySource);
}
static class MySource {
private EventListener listener;
void registerListener(EventListener eventListener) {
this.listener = eventListener;
}
void eventCome(Event e) {
if (listener != null) {
listener.onEvent(e);
} else {
System.out.println("还未初始化完毕");
}
}
}
interface EventListener {
void onEvent(Event e);
}
interface Event {
}
}
解决:
public class MultiThreadsError7 {
int count;
private EventListener listener;
private MultiThreadsError7(MySource source) {
listener = new EventListener() {
@Override
public void onEvent(MultiThreadsError5.Event e) {
System.out.println("\n我得到的数字是" + count);
}
};
for (int i = 0; i < 10000; i++) {
System.out.print(i);
}
count = 100;
}
public static MultiThreadsError7 getInstance(MySource source) {
MultiThreadsError7 safeListener = new MultiThreadsError7(source);
source.registerListener(safeListener.listener);
return safeListener;
}
public static void main(String[] args) {
MySource mySource = new MySource();
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
mySource.eventCome(new MultiThreadsError5.Event() {
});
}
}).start();
MultiThreadsError7 multiThreadsError7 = new MultiThreadsError7(mySource);
}
static class MySource {
private EventListener listener;
void registerListener(EventListener eventListener) {
this.listener = eventListener;
}
void eventCome(MultiThreadsError5.Event e) {
if (listener != null) {
listener.onEvent(e);
} else {
System.out.println("还未初始化完毕");
}
}
}
interface EventListener {
void onEvent(MultiThreadsError5.Event e);
}
interface Event {
}
}
public class MultiThreadsError6 {
private Map<String, String> states;
public MultiThreadsError6() {
new Thread(new Runnable() {
@Override
public void run() {
states = new HashMap<>();
states.put("1", "周一");
states.put("2", "周二");
states.put("3", "周三");
states.put("4", "周四");
}
}).start();
}
public Map<String, String> getStates() {
return states;
}
public static void main(String[] args) throws InterruptedException {
MultiThreadsError6 multiThreadsError6 = new MultiThreadsError6();
// 造成时间不同执行不同
Thread.sleep(1000);
System.out.println(multiThreadsError6.getStates().get("1"));
}
}
如何解决逸出
什么是性能问题、性能问题有哪些体现?
为什么多线程会带来性能问题
什么是上下文?:保存现场
缓存开销:缓存失效
何时会导致密集的上下文切换:抢锁、IO
参考
https://coding.imooc.com/class/362.html
领取专属 10元无门槛券
私享最新 技术干货