多线程2之线程原子性问题-以及解决方案
2021-01-13 17:38:30 0 举报
多线程
作者其他创作
大纲/内容
这个是对当前对象的加锁,属于对象锁
这个就不会出现锁的互斥性问题,因为是对两个不同的对象做的加锁操作
综合上边的知识我们可以通过下面三种方式来加锁,保证原子性
ThreadB
count++
加锁
释放锁
CPU
加锁,保证了排他性
count=0寄存器
如何判断一个数据是否会产生线程安全问题?
互斥锁的本质是什么?
14: getstatic #7 // Field a:I 17: iconst_1 18: iadd 19: putstatic #7 // Field a:I
线程切换导致了线程的原子性问题
类锁,对象锁
ThreadA
count=1写入内存
package com.john.thread;public class ThreadDemo1 { public static int a = 0; public static void addNum() { try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } Object o = new Object(); synchronized (o) { a++; } } public static void main(String[] args) throws InterruptedException { for (int i = 0; i < 1000; i++) { new Thread(() -> ThreadDemo1.addNum()).start(); } Thread.sleep(3000);//保证线程执行完 System.out.println(\"执行结果: \" + a); }}
线程切换
锁的状态和标记
采用javap -v ThreadDemo1.class
像上面这几行字节码就是体现了原子性,但是由于线程频繁切换导致了原子性的破快,而造成结果错误
package com.john.thread;public class ThreadDemo1 { public static int a = 0; private static Object o = new Object(); public static void addNum() { try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (o) { a++; } } public static void main(String[] args) throws InterruptedException { for (int i = 0; i < 1000; i++) { new Thread(() -> ThreadDemo1.addNum()).start(); } Thread.sleep(3000);//保证线程执行完 System.out.println(\"执行结果: \" + a); }}
区别于左边的,像这种就可以实现互斥,因为静态的对象只有一个
1、会有多个线程同时访问一个数据吗2、数据的使用
package com.john.thread;public class ThreadDemo1 { public static int a= 0; public static void addNum(){ try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } a++; } public static void main(String[] args) throws InterruptedException { for (int i=0;i<1000;i++){ new Thread(()->{ ThreadDemo1.addNum(); }).start(); } Thread.sleep(3000);//保证线程执行完 System.out.println(a); }}
测试答案永远小于等于1000,至于小于1000原因就是因为线程的切换破坏了线程的原子性导致的
三者不同在于作用的范围不同
通过字节码看原因
application.java
parse and load
解决上面的问题的方法可以通过锁来处理
package com.john.thread;public class ThreadDemo1 { public static int a = 0; public static void addNum() { try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (ThreadDemo1.class) { a++; } } public static void main(String[] args) throws InterruptedException { for (int i = 0; i < 1000; i++) { new Thread(() -> ThreadDemo1.addNum()).start(); } Thread.sleep(3000);//保证线程执行完 System.out.println(\"执行结果: \" + a); }}
package com.john.thread;public class ThreadDemo1 { public static int a= 0; public static void addNum(){ synchronized (ThreadDemo1.class) { try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } a++; } } public static void main(String[] args) throws InterruptedException { for (int i=0;i<1000;i++){ new Thread(()->ThreadDemo1.addNum()).start(); } Thread.sleep(3000);//保证线程执行完 System.out.println(\"执行结果: \"+a); }}
临界区
Object o = new Object()
注意:像下面的这种就达不到互斥的作用的,因为1000个线程就会存在1000个对象的
共享资源
受保护资源的锁(锁对象)
受保护的资源
单核也会有这个问题,因为是线程切换导致的
package com.john.thread;public class ThreadDemo1 { public static int a= 0; public synchronized static void addNum(){ try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } a++; } public static void main(String[] args) throws InterruptedException { for (int i=0;i<1000;i++){ new Thread(()->ThreadDemo1.addNum()).start(); } Thread.sleep(3000);//保证线程执行完 System.out.println(\"执行结果: \"+a); }}
例子
ThreadC
锁的互斥性
类锁
0 条评论
下一页