多线程编程
多线程编程,我这边找到三类题
- 多线程操作同一个变量
- 多线程循环打印ABC
- 多线程实现生产者消费者模式
踩坑
这里有一个坑,除了main线程和自己创建的线程,会多出来一个
Monitor
这个线程是IDEA的,而且只有启动运行才有,调试运行没
多线程操作同一个变量
题目描述:利用100个线程,每个线程将一个数字自增1000次,最终把这个数字加到100000
这应该是三个题里面最简单的
原始写法
可以看到,这里无论运行几次,始终小于预期的100000
个人分析主要是因为线程的运行并不是严格按序进行的,可能上一个线程的100次还没加完没执行完,下一个线程就读来加了
++操作并不是原子操作
public class RowTest { public int num =0; public void increase(){ num++; } public static void main(String[] args) { final RowTest rowTest = new RowTest(); for(int i = 0;i<100;i++){ new Thread(()->{ for(int j=0;j<1000;j++) rowTest.increase(); }).start(); } while (Thread.activeCount()>1) Thread.yield(); System.out.println(rowTest.num); } }
另外这里num变量其实加不加volatile
没有区别,按理来说我的笔记里volatile
可以使变量对多个线程可见,那这里是我的写法有问题吗?什么情况下变量对线程不可见,加了volatile
又可见了呢?
有没有可能是这样,new出来的线程操作的是main线程实例化出的volatileTest对象,对象是在堆区创建的,堆区是共享内存区,所以其他线程才可以操作main线程new出来的对象,实例变量num不属于任何一个线程,它属于volatile对象
那么我不用线程操作对象,直接用线程操作变量吗?
这里很奇怪,这个a是怎么传过去的?为什么又不让修改?
Synchronized
关键字解决
正确输出
public class SynchronizedTest { public int num = 0; public synchronized void increase(){ num++; } public static void main(String[] args) { SynchronizedTest synchronizedTest = new SynchronizedTest(); for(int i =0;i<100;i++){ new Thread(()->{ for(int j=0;j<100;j++) synchronizedTest.increase(); }).start(); } while (Thread.activeCount()>1) Thread.yield(); System.out.println(synchronizedTest.num); } }
那么问题又来了,我知道Synchrozied
代码块需要一把锁,多个线程共享的对象,那么Synchrozied
方法究竟锁住的是谁?
结论上来说:
- 静态方法上锁住的是类
锁住类是个什么说法???
- 实例方法上锁住的是当前对象
- 静态代码块
这个比较复杂,待会儿再说
说回来,那么这里锁住的就是调用increase()
方法的synchronizedTset
实例对象,这个实例对象是唯一的
Lock接口解决
public class LockTest { public int num; ReentrantLock lock = new ReentrantLock(); public void increase(){ lock.lock(); try { num++; }finally { lock.unlock(); } } public static void main(String[] args) { LockTest lockTest = new LockTest(); for(int i = 0;i<100;i++){ new Thread(()->{ for(int j = 0;j<100;j++) lockTest.increase(); }).start(); } while (Thread.activeCount()>1) Thread.yield(); System.out.println(lockTest.num); } }
原子类解决
public class AtomicTest { public AtomicInteger num = new AtomicInteger(0); public void increase(){ num.incrementAndGet(); } public static void main(String[] args) { AtomicTest atomicTest = new AtomicTest(); for(int i = 0;i<100;i++){ new Thread(()->{ for(int j = 0;j<100;j++) atomicTest.increase(); }).start(); } while (Thread.activeCount()>1) Thread.yield(); System.out.println(atomicTest.num); } }
最后,volatile
关键字又涉及到一个单例模式双重锁
本文作者:YaosGHC
本文链接:https://www.cnblogs.com/yaocy/p/16775967.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步