多线程编程

多线程编程,我这边找到三类题

  1. 多线程操作同一个变量
  2. 多线程循环打印ABC
  3. 多线程实现生产者消费者模式

踩坑

这里有一个坑,除了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方法究竟锁住的是谁?

结论上来说:

  1. 静态方法上锁住的是类

锁住类是个什么说法???

  1. 实例方法上锁住的是当前对象
  2. 静态代码块

这个比较复杂,待会儿再说

说回来,那么这里锁住的就是调用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 中国大陆许可协议进行许可。

posted @   YaosGHC  阅读(41)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起