zxyy2627
Lucky丶钉钉
采纳率71.4%
2019-08-11 20:26

Java多线程公平锁问题

5
已采纳

Java多线程中Reentrant类的带参构造器,创建一个公平锁,按道理说线程应该是先进先出的原则,为什么打印会是乱序。求解答:

package cn.zxyy.multiThread.chap4.ReentrantLock.Fair_noFair_test;

import java.util.concurrent.locks.ReentrantLock;

public class Service {
    private ReentrantLock lock;

    public Service(boolean isFair){
        lock = new ReentrantLock(isFair);
    }

    public void serviceMethod(){
        try{
            lock.lock();
            System.out.println("ThreadName = " +Thread.currentThread().getName()+"获得锁定");
        }finally {
            lock.unlock();
        }
    }
}
package cn.zxyy.multiThread.chap4.ReentrantLock.Fair_noFair_test;

public class RunFair {
    public static void main(String[] args) {
        final Service service = new Service(true);
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("♠线程"+Thread.currentThread().getName() +"运行了");
                service.serviceMethod();
            }
        };
        Thread[] threads = new Thread[10];
        for (int i = 0; i < 10; i++) {
            threads[i] = new Thread(runnable);
        }
        for (int i = 0; i < 10; i++) {
            threads[i].start();
        }
    }
}

图片说明

使用的是IntellijIdea2017会和这个工具的设置有关系吗?

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

5条回答

  • sw19930104 asafer 2年前

    其实楼主搞混了两个概念,一个是线程创建的顺序和公平锁的概念搞混了,先说线程创建的顺序,我们现在用的都是多核机器,所以楼主的创建
    线程的方法是无法保证线程创建顺序按照1 2,3,4,5,6来的,他是由cpu自己调度的,及时是单核机子,也会使用时间片轮转调度,所以楼主的创建
    线程方法无法保证创建线程,第二个问题是公平锁的问题,当线程创建后才去请求锁,公平锁可以保证请求锁的顺序,在实际生产过程中创建顺序
    没有太大的意义的,更多的是关注线程的执行顺序,线程执行顺序可以用join,countDownLatch,syclicBarrier,lockSupport ,阻塞等方法保证执行顺

    点赞 评论 复制链接分享
  • github_39483621 github_39483621 2年前

    其实所谓的公平锁是在Lock那个函数执行的顺序上是公平的,谁先到阻塞谁先拿锁,但是之前的代码,包含start()包含打印“...启动了”各个线程都是在争夺
    cpu时间片的,如果你把代码改成

     public void serviceMethod()throws InterruptedException{
            try{
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName()+"启动");
                lock.lock();
    
    

    如上代码,因为线程睡眠再唤醒的时间远远大于后面打印语句的时间,所以基本可以通过看这个打印得到排队的顺序,就是跟获得锁顺序一样了

    点赞 评论 复制链接分享
  • qiangchen1990 qiangchen1990 2年前

    没明白“按道理说线程应该是先进先出的原则”。

    我个人的理解:
    1、线程的启动是由CPU调度的,在一定程度上是无序的。

    2、线程应该是在获取到锁后再执行自己的逻辑,因此我改的代码是:
     ```
         public void serviceMethod() {
        try {
            lock.lock();
            System.out.println("ThreadName = " + Thread.currentThread().getName() + "获得锁定");
            System.out.println("♠线程"+Thread.currentThread().getName() +"运行了");
        } finally {
            lock.unlock();
        }
    }
     ```
     输出的结果:
     ThreadName = Thread-1获得锁定
    ♠线程Thread-1运行了
    ThreadName = Thread-2获得锁定
    ♠线程Thread-2运行了
    ThreadName = Thread-5获得锁定
    ♠线程Thread-5运行了
    ThreadName = Thread-6获得锁定
    ....
    
    点赞 评论 复制链接分享
  • wojiushiwo945you 毕小宝 2年前

    乱序可能可能鞥锁没有关系,而是跟线程启动的先后顺序有关系,你用 for 循环创建了 10 个线程,可能它们的启动顺序跟创建创建顺序不一致。
    修改下启动代码,休眠一会儿再启动其他线程。我正在写一篇多线程的众筹文章,有兴趣可以点击这里看看多线程并发编程实践分析

    public static void main(String[] args) {
            final Service service = new Service(true);
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    System.out.println(new Date()+"♠线程"+Thread.currentThread().getName() +"运行了");
                    service.serviceMethod();
                }
            };
            Thread[] threads = new Thread[10];
            for (int i = 0; i < 10; i++) {
                threads[i] = new Thread(runnable);
            }
            for (int i = 0; i < 10; i++) {
                threads[i].start();
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    

    这样就是顺序获取锁和启动的过程了。

    点赞 评论 复制链接分享
  • dabocaiqq dabocaiqq 2年前
    点赞 评论 复制链接分享

为你推荐