JAVA中,关于多线程的疑惑,求解答

发布于 2022-09-11 19:20:49 字数 2327 浏览 19 评论 0

JAVA中,关于多线程的疑惑

疑惑来源于网上文章的阅读,和自己的测试

来源于网上的测试代码

public class Runnable1 implements Runnable{
    private static int count = 0;

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(new Runnable1());
            thread.start();
        }
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("result: " + count);
    }

    @Override
    public void run() {
        synchronized (this){
            for (int i = 0; i < 10000; i++) {
                count++;
            }
        }

    }

}

描述

该文章是一个描述synchronized关键字的文章,文章说对于count这个共享变量,以synchronized来锁住当前对象保证并发访问的原子性,但是也让我产生了疑惑,为什么一定要访问本类中的变量,如果线程访问一个普通的类,比如user(举例而已)这样的java bean对象,由于java bean中的属性都是私有的,那么只能通过get/set方法访问,那么如果我锁住的是该bean的class对象是否可以保证,并发访问的正确性呢?

我做了测试,代码如下

public class Test {
    private static  int value = 0;

    public  static int getValue() {
        return value;
    }

    public  static void setValue(int value) {
        Test.value = value;
    }

    public static void main(String[] args) {
        ThreadFactory factory = new ThreadFactoryBuilder().setNameFormat("threadPool-%d").build();
        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 10, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(10),
                factory, new ThreadPoolExecutor.AbortPolicy());
        poolExecutor.execute(new Thread1());
        poolExecutor.execute(new Thread1());
        poolExecutor.execute(new Thread1());
        poolExecutor.execute(new Thread1());
        poolExecutor.execute(new Thread1());
        poolExecutor.shutdown();

        System.out.println(value);
    }

}

public class Thread1 extends Thread{

    @Override
    public void run() {

    synchronized (Thread.class){
        for (int i = 0; i < 100; i++) {
            int value = Test.getValue();
            ++value;
            Test.setValue(value);

        }
    }

    }

}

描述以及之后的修改

按照一样的思路,这里我修饰的是Test.class对象,测试结果不一致
之后尝试将bean的get/set方法也使用synchronized修饰,发现得到的结果依然不一致

开始怀疑自己的理解有问题

难道sychronized不是将访问的线程都自进入该对象时就加上锁吗???

求指点,万分感谢

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

痴情 2022-09-18 19:20:49

锁一个全局变量并没有问题, 问题是

poolExecutor.shutdown();

线程都还没执行完呢,你直接把它干掉了,输出能对么

眼趣 2022-09-18 19:20:49

后面这段代码?哪里加锁了?
synchronized的目的是保证代码块的原子性操作

以synchronized来锁住当前对象保证并发访问的原子性,但是也让我产生了疑惑,为什么一定要访问本类中的变量,
这句话就很莫名?完全看不懂你想问什么

当梦初醒 2022-09-18 19:20:49

应该是两方面原因:
第一:你显式的使用了shutdown(),此时线程可能还在跑你就给干掉了,当然预期结果不一样
第二:即使不使用shutdown,你提交线程之后马上进行了System.out.println(value);此时预期结果也不一样,因为提交线程之后是异步去跑的,所以此时的主线程(就是这个main方法)不会等待之前的线程是否跑完就会直接进行输出了。所以预期结果不一样。

你可以再看看上面的demo代码,它有一个Thread.sleep(500),然后再输出;其实这个主线程等500ms的目的就是让子线程能够跑完,然后输出。假如demo代码的线程500ms跑不完,他的value结果也是不对的。你可以修改demo代码如下:主要修改是在run方法中加了Thread.sleep(1),保证这个线程在500ms跑不完。

public class Runnable1 implements Runnable{
    private static int count = 0;

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            Thread thread = new Thread(new Runnable1());
            thread.start();
        }
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("result: " + count);
    }

    @Override
    public void run() {
        synchronized (this){
            for (int i = 0; i < 10000; i++) {
                count++;
                // 这是新增的代码,意识是:count加1之后休眠1ms
                try {
                    Thread.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }

    }

}

综上你把你的main代码修改如下看看,变动点有2个:

  1. 删除shutdown
  2. 在输出之前让主线程sleep一下,保证子线程执行完。
public static void main(String[] args) {
        ThreadFactory factory = new ThreadFactoryBuilder().setNameFormat("threadPool-%d").build();
        ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 10, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(10),
                factory, new ThreadPoolExecutor.AbortPolicy());
        poolExecutor.execute(new Thread1());
        poolExecutor.execute(new Thread1());
        poolExecutor.execute(new Thread1());
        poolExecutor.execute(new Thread1());
        poolExecutor.execute(new Thread1());
        
        try {
            Thread.slepp(2000);
        } catch (InterruptedException e){
            
        }

        System.out.println(value);
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文