多个线程同时调用一个synchronized方法时,发现是后调用这个方法的先被调度执行了

LFYer 2016-02-28 12:13:19
加精
直接上代码

import java.util.concurrent.TimeUnit;

class MyThread implements Runnable {

private Queue queue;

public MyThread(Queue queue) {
this.queue = queue;
}

@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName() + " invode queue.print()");
this.queue.print();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

public class SyncQueue {

public static void main(String[] args) throws InterruptedException {
Queue queue = new Queue();
for (int i = 0; i < 10; i++) {
new Thread(new MyThread(queue)).start();
TimeUnit.MILLISECONDS.sleep(100);
}
}
}

class Queue {
synchronized public void print() throws InterruptedException {
TimeUnit.SECONDS.sleep(3);
System.out.println(Thread.currentThread().getName() + " return");
}
}


程序输出:

Thread-0 invoke queue.print()
Thread-1 invoke queue.print()
Thread-2 invoke queue.print()
Thread-3 invoke queue.print()
Thread-4 invoke queue.print()
Thread-5 invoke queue.print()
Thread-6 invoke queue.print()
Thread-7 invoke queue.print()
Thread-8 invoke queue.print()
Thread-9 invoke queue.print()
Thread-0 return
Thread-9 return
Thread-8 return
Thread-7 return
Thread-6 return
Thread-5 return
Thread-4 return
Thread-3 return
Thread-2 return
Thread-1 return



10个线程同时去执行一个被synchronized修饰的方法,而且我故意让线程从1到10有序的调用调用这个方法,但是从输出结果来看,都是后调用这个方法的线程先被调度执行了,多次运行该程序的结果都是这样,请问这是为什么?
...全文
7829 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
qq_29114481 2017-11-10
  • 打赏
  • 举报
回复
虽然线程按顺序创建,但是queue类里面的sleep,导致了后面创建的线程与前面创建的线程一起等待锁,谁能抢到锁就不一定了,但第一个创建的线程肯定是第一个抢到锁。你可以试着在线程创建后让它等待一些时间,避免后面的线程追上前面的线程。
Ashitaka-San 2016-03-05
  • 打赏
  • 举报
回复
程序错的很多,有个简单的改法:
1.每次new Thread之后的睡100ms.去掉,
1. 把class Queue下边的同步方法前边加上static。
二者缺一不可
May的博客 2016-03-03
  • 打赏
  • 举报
回复
5楼的回复太赞了,我也遇到一个类似的问题,刚好可以解决了~ 抱歉,刚才的答案很无脑。 想了一段时间,又查了一些资料,简单说一下我的想法: 1. synchornized不是公平锁,即不按先到先得的方式获得锁; 2. synchornized的是轻量级锁的实现,底层实现主要依靠Lock-Free的栈(ContentionList,一个后进先出(LIFO)的栈) 参考资料: http://blog.csdn.net/chen77716/article/details/6618779 http://www.majin163.com/2014/03/17/synchronized2/?utm_source=tuicool&utm_medium=referral
CaiHongLa 2016-03-02
  • 打赏
  • 举报
回复
qq_1021540607 2016-03-02
  • 打赏
  • 举报
回复
cattpon 2016-03-02
  • 打赏
  • 举报
回复
引用 5 楼 tianxiexingyun 的回复:
抱歉,刚才的答案很无脑。 想了一段时间,又查了一些资料,简单说一下我的想法: 1. synchornized不是公平锁,即不按先到先得的方式获得锁; 2. synchornized的是轻量级锁的实现,底层实现主要依靠Lock-Free的栈(ContentionList,一个后进先出(LIFO)的栈) 参考资料: http://blog.csdn.net/chen77716/article/details/6618779 http://www.majin163.com/2014/03/17/synchronized2/?utm_source=tuicool&utm_medium=referral
引用 5 楼 tianxiexingyun 的回复:
抱歉,刚才的答案很无脑。 想了一段时间,又查了一些资料,简单说一下我的想法: 1. synchornized不是公平锁,即不按先到先得的方式获得锁; 2. synchornized的是轻量级锁的实现,底层实现主要依靠Lock-Free的栈(ContentionList,一个后进先出(LIFO)的栈) 参考资料: http://blog.csdn.net/chen77716/article/details/6618779 http://www.majin163.com/2014/03/17/synchronized2/?utm_source=tuicool&utm_medium=referral
正解~
猿敲月下码 2016-03-02
  • 打赏
  • 举报
回复
这里使用了private Lock lock = new ReentrantLock(true);也就是安全锁 把sleep去掉也没关系,return的顺序肯定是根据invoke的顺序来的。
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class MyThread implements Runnable {

	private Queue queue;

	public MyThread(Queue queue) {
		this.queue = queue;
	}

	@Override
	public void run() {
		try {
			System.out.println(Thread.currentThread().getName()
					+ " invode queue.print()");
			this.queue.print();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

public class SyncQueue {

	public static void main(String[] args) throws InterruptedException {
		Queue queue = new Queue();
		for (int i = 0; i < 10; i++) {
			new Thread(new MyThread(queue)).start();
		}
	}
}

class Queue {
	private Lock lock = new ReentrantLock(true);

	public void print() throws InterruptedException {
		try {
			lock.lock();
			System.out.println(Thread.currentThread().getName() + " return");
		} finally {
			lock.unlock();
		}
	}
}
猿敲月下码 2016-03-02
  • 打赏
  • 举报
回复
公平锁和非公平锁的问题 公平锁表示线程获取顺序遵循FIFO,非公平锁则是随机获得锁 如果要实现公平锁可以用Lock lock = new ReentrantLock(true);
kiyoki 2016-03-02
  • 打赏
  • 举报
回复
从java层面来看,结果应该是乱序的,间隔太小无法判断谁先抢到锁
stenger 2016-03-01
  • 打赏
  • 举报
回复
for (int i = 0; i < 10; i++) { Queue queue = new Queue(); new Thread(new MyThread(queue)).start(); TimeUnit.MILLISECONDS.sleep(100); } 这块 把创建对象放到循环里面去 synchronized 同步 锁的是对象
LFYer 2016-02-29
  • 打赏
  • 举报
回复
引用 5 楼 tianxiexingyun 的回复:
抱歉,刚才的答案很无脑。 想了一段时间,又查了一些资料,简单说一下我的想法: 1. synchornized不是公平锁,即不按先到先得的方式获得锁; 2. synchornized的是轻量级锁的实现,底层实现主要依靠Lock-Free的栈(ContentionList,一个后进先出(LIFO)的栈) 参考资料: http://blog.csdn.net/chen77716/article/details/6618779 http://www.majin163.com/2014/03/17/synchronized2/?utm_source=tuicool&utm_medium=referral
多谢,我这个周末再看看,晚点再结帖!
me阿木 2016-02-28
  • 打赏
  • 举报
回复
抱歉,刚才的答案很无脑。 想了一段时间,又查了一些资料,简单说一下我的想法: 1. synchornized不是公平锁,即不按先到先得的方式获得锁; 2. synchornized的是轻量级锁的实现,底层实现主要依靠Lock-Free的栈(ContentionList,一个后进先出(LIFO)的栈) 参考资料: http://blog.csdn.net/chen77716/article/details/6618779 http://www.majin163.com/2014/03/17/synchronized2/?utm_source=tuicool&utm_medium=referral
me阿木 2016-02-28
  • 打赏
  • 举报
回复
引用 3 楼 tianxiexingyun 的回复:
很简单啊,你给了每个线程充分的完成时间。 一个线程完成后,另一个线程未必开始新建就绪呢。 把主线程创建启动线程循环中的sleep去掉再试。

package com.zhyea.test;

import java.util.concurrent.TimeUnit;

class MyThread implements Runnable {

	private Queue queue;

	public MyThread(Queue queue) {
		this.queue = queue;
	}

	@Override
	public void run() {
		try {
			System.out.println(Thread.currentThread().getName() + " invode queue.print()");
			this.queue.print();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

public class MyTest {

	public static void main(String[] args) throws InterruptedException {
		Queue queue = new Queue();
		for (int i = 0; i < 10; i++) {
			new Thread(new MyThread(queue)).start();
		}
	}
}

class Queue {
	synchronized public void print() throws InterruptedException {
		TimeUnit.SECONDS.sleep(3);
		System.out.println(Thread.currentThread().getName() + " return");
	}
}
执行了一半我就停止运行了,也能说明问题了:

Thread-1 invode queue.print()
Thread-5 invode queue.print()
Thread-4 invode queue.print()
Thread-0 invode queue.print()
Thread-3 invode queue.print()
Thread-2 invode queue.print()
Thread-7 invode queue.print()
Thread-6 invode queue.print()
Thread-8 invode queue.print()
Thread-9 invode queue.print()
抱歉看错问题了
me阿木 2016-02-28
  • 打赏
  • 举报
回复
很简单啊,你给了每个线程充分的完成时间。 一个线程完成后,另一个线程未必开始新建就绪呢。 把主线程创建启动线程循环中的sleep去掉再试。

package com.zhyea.test;

import java.util.concurrent.TimeUnit;

class MyThread implements Runnable {

	private Queue queue;

	public MyThread(Queue queue) {
		this.queue = queue;
	}

	@Override
	public void run() {
		try {
			System.out.println(Thread.currentThread().getName() + " invode queue.print()");
			this.queue.print();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

public class MyTest {

	public static void main(String[] args) throws InterruptedException {
		Queue queue = new Queue();
		for (int i = 0; i < 10; i++) {
			new Thread(new MyThread(queue)).start();
		}
	}
}

class Queue {
	synchronized public void print() throws InterruptedException {
		TimeUnit.SECONDS.sleep(3);
		System.out.println(Thread.currentThread().getName() + " return");
	}
}
执行了一半我就停止运行了,也能说明问题了:

Thread-1 invode queue.print()
Thread-5 invode queue.print()
Thread-4 invode queue.print()
Thread-0 invode queue.print()
Thread-3 invode queue.print()
Thread-2 invode queue.print()
Thread-7 invode queue.print()
Thread-6 invode queue.print()
Thread-8 invode queue.print()
Thread-9 invode queue.print()
贝拉的魔法 2016-02-28
  • 打赏
  • 举报
回复
我也很好奇为什么会这样,明天我也去试试

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧