多线程编程

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

  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关键字又涉及到一个单例模式双重锁

posted @ 2022-10-10 15:41  YaosGHC  阅读(45)  评论(0)    收藏  举报