为什么代码没问题,却一直执行第一个线程?

package ccc;

import java.util.concurrent.locks.ReentrantLock;

public class LockTest {
    public static void main(String[] args) {
        Window w1 = new Window();

        Thread a = new Thread(w1);
        Thread b = new Thread(w1);
        Thread c = new Thread(w1);

        a.setName("窗口");
        b.setName("移动");
        c.setName("黄牛");

        a.start();
        b.start();
        c.start();
    }

}

class Window implements Runnable{
    private int ticket = 100;
    private ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while(true) {
            try {
                lock.lock();

                if (ticket > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }

                    System.out.println(Thread.currentThread().getName() + ":" + ticket);
                    ticket--;
                } else {
                    break;
                }
            }finally {
                lock.unlock();
            }
        }
    }
}






"D:\Program Files\Java\jdk1.8.0_231\bin\java.exe" "-javaagent:D:\JAVA学习\idea\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=60585:D:\JAVA学习\idea\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath "D:\Program Files\Java\jdk1.8.0_231\jre\lib\charsets.jar;D:\Program Files\Java\jdk1.8.0_231\jre\lib\deploy.jar;D:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\access-bridge-64.jar;D:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\cldrdata.jar;D:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\dnsns.jar;D:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\jaccess.jar;D:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\jfxrt.jar;D:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\localedata.jar;D:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\nashorn.jar;D:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\sunec.jar;D:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\sunjce_provider.jar;D:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\sunmscapi.jar;D:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\sunpkcs11.jar;D:\Program Files\Java\jdk1.8.0_231\jre\lib\ext\zipfs.jar;D:\Program Files\Java\jdk1.8.0_231\jre\lib\javaws.jar;D:\Program Files\Java\jdk1.8.0_231\jre\lib\jce.jar;D:\Program Files\Java\jdk1.8.0_231\jre\lib\jfr.jar;D:\Program Files\Java\jdk1.8.0_231\jre\lib\jfxswt.jar;D:\Program Files\Java\jdk1.8.0_231\jre\lib\jsse.jar;D:\Program Files\Java\jdk1.8.0_231\jre\lib\management-agent.jar;D:\Program Files\Java\jdk1.8.0_231\jre\lib\plugin.jar;D:\Program Files\Java\jdk1.8.0_231\jre\lib\resources.jar;D:\Program Files\Java\jdk1.8.0_231\jre\lib\rt.jar;D:\JAVA学习\SGG\2020最新学习路线图\out\production\diedline" day2.LockTest
窗口:100
窗口:99
窗口:98
窗口:97
窗口:96
窗口:95
窗口:94
窗口:93
窗口:92
窗口:91
窗口:90
窗口:89
窗口:88
窗口:87
窗口:86
窗口:85
窗口:84
窗口:83
窗口:82
窗口:81
窗口:80
窗口:79
窗口:78
窗口:77
窗口:76
窗口:75
窗口:74
窗口:73
窗口:72
窗口:71
窗口:70
窗口:69
窗口:68
窗口:67
窗口:66
窗口:65
窗口:64
窗口:63
窗口:62
窗口:61
窗口:60
窗口:59
窗口:58
窗口:57
窗口:56
窗口:55
窗口:54
窗口:53
窗口:52
窗口:51
窗口:50
窗口:49
窗口:48
窗口:47
窗口:46
窗口:45
窗口:44
窗口:43
窗口:42
窗口:41
窗口:40
窗口:39
窗口:38
窗口:37
窗口:36
窗口:35
窗口:34
窗口:33
窗口:32
窗口:31
窗口:30
窗口:29
窗口:28
窗口:27
窗口:26
窗口:25
窗口:24
窗口:23
窗口:22
窗口:21
窗口:20
窗口:19
窗口:18
窗口:17
窗口:16
窗口:15
窗口:14
窗口:13
窗口:12
窗口:11
窗口:10
窗口:9
窗口:8
窗口:7
窗口:6
窗口:5
窗口:4
窗口:3
窗口:2
窗口:1









 

sleep 的时候lock还在持有锁,其他线程获取不到锁,你可以sleep之前unlock下,sleep之后再次lock下。另外,你的lock锁的资源是什么?一般lock只应发生在对资源读写的地方做保护,而不应该锁整个方法(行为),这个粒度太大了,性能不好也有问题

class LockTest {

	public static void main(String[] args) {
		Window w1 = new Window();
		Thread a = new Thread(w1);
		Thread b = new Thread(w1);
		Thread c = new Thread(w1);
		a.setName("窗口");
		b.setName("移动");
		c.setName("黄牛");
		a.start();
		b.start();
		c.start();
	}

}

class Window implements Runnable {
	private int ticket = 100;
	private ReentrantLock lock = new ReentrantLock();

	@Override
	public void run() {
		while (true) {
			try {
				lock.lock();
				if (ticket > 0) {
					System.out.println(Thread.currentThread().getName() + ":" + ticket);
					ticket--;					
				} else {
					break;
				}
			} finally {
				lock.unlock();
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

		}

	}

}

 

sleep不会释放锁,你在36行那块的sleep加不加没什么影响,你加了sleep,只是暂停了当前的执行的线程,当前线程还是占领cpu资源的,结束后依旧执行的是刚刚暂停的进程,想要模拟网络延迟可以像其他人说的一样,加sleep放在锁的外面

可能是sleep的时间太短了

跟sleep的原因并不大,ReentrantLock内部初始化的时候默认是非公平锁,导致任意一个线程都有机会获得CPU的使用权,可能线程A更具有竞争力,可以改成加个reentrantLock改成公平锁试试

用你代码跑了一下,结果却是符合预期的:

窗口:100
移动:99
黄牛:98
窗口:97
移动:96
移动:95
黄牛:94
窗口:93
窗口:92
移动:91
黄牛:90
窗口:89
移动:88
移动:87
黄牛:86
窗口:85
移动:84
黄牛:83
黄牛:82
窗口:81
移动:80
黄牛:79
窗口:78
移动:77
黄牛:76
黄牛:75
窗口:74
移动:73
黄牛:72
窗口:71
移动:70
移动:69
移动:68
黄牛:67
黄牛:66
窗口:65
窗口:64
移动:63
黄牛:62
窗口:61
移动:60
移动:59
移动:58
移动:57
黄牛:56
黄牛:55
黄牛:54
黄牛:53
黄牛:52
窗口:51
窗口:50
窗口:49
窗口:48
窗口:47
移动:46
黄牛:45
窗口:44
移动:43
黄牛:42
窗口:41
窗口:40
窗口:39
移动:38
黄牛:37
窗口:36
窗口:35
窗口:34
窗口:33
窗口:32
移动:31
移动:30
移动:29
移动:28
移动:27
移动:26
移动:25
移动:24
移动:23
黄牛:22
黄牛:21
窗口:20
窗口:19
窗口:18
窗口:17
窗口:16
窗口:15
移动:14
黄牛:13
窗口:12
移动:11
移动:10
黄牛:9
黄牛:8
窗口:7
移动:6
移动:5
移动:4
黄牛:3
窗口:2
移动:1

 

你用的这个采用的是非公平锁机制,第一次拿到的,第二次拿到的概率会比较大,所以就一直执行第一个,你把睡眠放到unlock下面,就可以看到抢锁的过程了