java synchronized问题

liuhu_pp 2014-04-04 01:57:39
s1.start();启动一个线程之后执行synchronized方法printAge(int),主线程s1.printAge() 执行结果为什么可以是这样,如图


class Student extends Thread {
private int age;

public Student(int age) {
this.age = age;
}

public synchronized void printAge(){

for(int i=0;i<10;i++){
System.err.println("age "+i+" is:"+age);
}
}

public synchronized void printAge(int age) {
//synchronized(this){
while (true){
System.out.println(age+"xxxxxxxxxxxxxxxxxxx");
try{
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//}

}

public void run() {
printAge(age);
}
}

class LoggingWidget {
public static void main(String args[]) {
Student s1 = new Student(1);
s1.start();
s1.printAge();
}
}


一种可能的结果
1xxxxxxxxxxxxxxxxxxx
age 0 is:1
age 1 is:1
age 2 is:1
age 3 is:1
age 4 is:1
age 5 is:1
age 6 is:1
age 7 is:1
age 8 is:1
age 9 is:1
1xxxxxxxxxxxxxxxxxxx
1xxxxxxxxxxxxxxxxxxx
.........

启动的线程持有对象锁 为什么主线程还可以进入??
...全文
587 31 打赏 收藏 转发到动态 举报
写回复
用AI写文章
31 条回复
切换为时间正序
请发表友善的回复…
发表回复
yuhouqingchen_2648 2014-06-06
  • 打赏
  • 举报
回复
引用 24 楼 fanslate 的回复:
我想我知道问题在哪了,一个线程用的是System.err,一个用的是System.out,这是不同的两个流,eclipse的控制台在输出的时候也许没有处理好,没有实时地输出。说几个方法,你都试试验证下:一个是同样的程序在命令行下测试;一个是统一使用System.out;一个是两个线程里不要输出i,都输出age++然后观察输出结果。
这个是正解!!!
zjfjfz 2014-04-05
  • 打赏
  • 举报
回复
楼主观点给力啊
liuhu_pp 2014-04-05
  • 打赏
  • 举报
回复
引用 28 楼 fanslate 的回复:
[quote=引用 27 楼 u014157407 的回复:] [quote=引用 26 楼 u014157407 的回复:] [quote=引用 25 楼 u014157407 的回复:] [quote=引用 24 楼 fanslate 的回复:] 我想我知道问题在哪了,一个线程用的是System.err,一个用的是System.out,这是不同的两个流,eclipse的控制台在输出的时候也许没有处理好,没有实时地输出。说几个方法,你都试试验证下:一个是同样的程序在命令行下测试;一个是统一使用System.out;一个是两个线程里不要输出i,都输出age++然后观察输出结果。
奇怪了 我在实验室运行同样的代码 总是出现交叉输出的 家里的电脑就是同步的 [/quote] 是的 说的很正确 代码改成这样


class Student extends Thread {
	private int age;

	public Student(int age) {
		this.age = age;
	}

	public synchronized void printAge() throws InterruptedException{
		Thread.sleep(5000);
		for(int i=0;i<10;i++){
			System.err.println("age "+i+" is:"+age);
		}
	}
	
	public synchronized void printAge(int age) {
		//synchronized(this){
			while (true){
				System.out.println(age+"xxxxxxxxxxxxxxxxxxx");
				try{
					Thread.sleep(5000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
			}
		//}
			
	}

	public void run() {
		printAge(age);
	}
}

class Sample {
	public static void main(String args[]) throws InterruptedException {
		Student s1 = new Student(1);
		//s1.start();
		s1.printAge();
		s1.start();
	}
}

每次都会交叉输出 按照你说的 SYSTEM.ERR改成SYSTEM.OUT就不会交叉了 就是同步了。。[/quote] 还是有点不懂 虽然是不同的输出流 但是也都是在synchronized里面 应该不会造成不同步啊?[/quote]我先说的最后一点你测试过没有?你代码里的输出只能说是输出顺序,不代表就是执行顺序。同一个流不管怎样肯定会顺序打印,两个流会如何同时打印在一个控制台上那就不确定了。[/quote] 明白了 谢谢。
byourfan 2014-04-04
  • 打赏
  • 举报
回复
引用 27 楼 u014157407 的回复:
[quote=引用 26 楼 u014157407 的回复:] [quote=引用 25 楼 u014157407 的回复:] [quote=引用 24 楼 fanslate 的回复:] 我想我知道问题在哪了,一个线程用的是System.err,一个用的是System.out,这是不同的两个流,eclipse的控制台在输出的时候也许没有处理好,没有实时地输出。说几个方法,你都试试验证下:一个是同样的程序在命令行下测试;一个是统一使用System.out;一个是两个线程里不要输出i,都输出age++然后观察输出结果。
奇怪了 我在实验室运行同样的代码 总是出现交叉输出的 家里的电脑就是同步的 [/quote] 是的 说的很正确 代码改成这样


class Student extends Thread {
	private int age;

	public Student(int age) {
		this.age = age;
	}

	public synchronized void printAge() throws InterruptedException{
		Thread.sleep(5000);
		for(int i=0;i<10;i++){
			System.err.println("age "+i+" is:"+age);
		}
	}
	
	public synchronized void printAge(int age) {
		//synchronized(this){
			while (true){
				System.out.println(age+"xxxxxxxxxxxxxxxxxxx");
				try{
					Thread.sleep(5000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
			}
		//}
			
	}

	public void run() {
		printAge(age);
	}
}

class Sample {
	public static void main(String args[]) throws InterruptedException {
		Student s1 = new Student(1);
		//s1.start();
		s1.printAge();
		s1.start();
	}
}

每次都会交叉输出 按照你说的 SYSTEM.ERR改成SYSTEM.OUT就不会交叉了 就是同步了。。[/quote] 还是有点不懂 虽然是不同的输出流 但是也都是在synchronized里面 应该不会造成不同步啊?[/quote]我先说的最后一点你测试过没有?你代码里的输出只能说是输出顺序,不代表就是执行顺序。同一个流不管怎样肯定会顺序打印,两个流会如何同时打印在一个控制台上那就不确定了。
liuhu_pp 2014-04-04
  • 打赏
  • 举报
回复
引用 26 楼 u014157407 的回复:
[quote=引用 25 楼 u014157407 的回复:] [quote=引用 24 楼 fanslate 的回复:] 我想我知道问题在哪了,一个线程用的是System.err,一个用的是System.out,这是不同的两个流,eclipse的控制台在输出的时候也许没有处理好,没有实时地输出。说几个方法,你都试试验证下:一个是同样的程序在命令行下测试;一个是统一使用System.out;一个是两个线程里不要输出i,都输出age++然后观察输出结果。
奇怪了 我在实验室运行同样的代码 总是出现交叉输出的 家里的电脑就是同步的 [/quote] 是的 说的很正确 代码改成这样


class Student extends Thread {
	private int age;

	public Student(int age) {
		this.age = age;
	}

	public synchronized void printAge() throws InterruptedException{
		Thread.sleep(5000);
		for(int i=0;i<10;i++){
			System.err.println("age "+i+" is:"+age);
		}
	}
	
	public synchronized void printAge(int age) {
		//synchronized(this){
			while (true){
				System.out.println(age+"xxxxxxxxxxxxxxxxxxx");
				try{
					Thread.sleep(5000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
			}
		//}
			
	}

	public void run() {
		printAge(age);
	}
}

class Sample {
	public static void main(String args[]) throws InterruptedException {
		Student s1 = new Student(1);
		//s1.start();
		s1.printAge();
		s1.start();
	}
}

每次都会交叉输出 按照你说的 SYSTEM.ERR改成SYSTEM.OUT就不会交叉了 就是同步了。。[/quote] 还是有点不懂 虽然是不同的输出流 但是也都是在synchronized里面 应该不会造成不同步啊?
liuhu_pp 2014-04-04
  • 打赏
  • 举报
回复
引用 25 楼 u014157407 的回复:
[quote=引用 24 楼 fanslate 的回复:] 我想我知道问题在哪了,一个线程用的是System.err,一个用的是System.out,这是不同的两个流,eclipse的控制台在输出的时候也许没有处理好,没有实时地输出。说几个方法,你都试试验证下:一个是同样的程序在命令行下测试;一个是统一使用System.out;一个是两个线程里不要输出i,都输出age++然后观察输出结果。
奇怪了 我在实验室运行同样的代码 总是出现交叉输出的 家里的电脑就是同步的 [/quote] 是的 说的很正确 代码改成这样


class Student extends Thread {
	private int age;

	public Student(int age) {
		this.age = age;
	}

	public synchronized void printAge() throws InterruptedException{
		Thread.sleep(5000);
		for(int i=0;i<10;i++){
			System.err.println("age "+i+" is:"+age);
		}
	}
	
	public synchronized void printAge(int age) {
		//synchronized(this){
			while (true){
				System.out.println(age+"xxxxxxxxxxxxxxxxxxx");
				try{
					Thread.sleep(5000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
			}
		//}
			
	}

	public void run() {
		printAge(age);
	}
}

class Sample {
	public static void main(String args[]) throws InterruptedException {
		Student s1 = new Student(1);
		//s1.start();
		s1.printAge();
		s1.start();
	}
}

每次都会交叉输出 按照你说的 SYSTEM.ERR改成SYSTEM.OUT就不会交叉了 就是同步了。。
liuhu_pp 2014-04-04
  • 打赏
  • 举报
回复
引用 24 楼 fanslate 的回复:
我想我知道问题在哪了,一个线程用的是System.err,一个用的是System.out,这是不同的两个流,eclipse的控制台在输出的时候也许没有处理好,没有实时地输出。说几个方法,你都试试验证下:一个是同样的程序在命令行下测试;一个是统一使用System.out;一个是两个线程里不要输出i,都输出age++然后观察输出结果。
奇怪了 我在实验室运行同样的代码 总是出现交叉输出的 家里的电脑就是同步的
byourfan 2014-04-04
  • 打赏
  • 举报
回复
我想我知道问题在哪了,一个线程用的是System.err,一个用的是System.out,这是不同的两个流,eclipse的控制台在输出的时候也许没有处理好,没有实时地输出。说几个方法,你都试试验证下:一个是同样的程序在命令行下测试;一个是统一使用System.out;一个是两个线程里不要输出i,都输出age++然后观察输出结果。
巫巫巫 2014-04-04
  • 打赏
  • 举报
回复
和楼主的执行情况不一样。 运行下面这个例子
class Student extends Thread {
	private int age;

	public Student(int age) {
		this.age = age;
	}

	public synchronized void printAge(){
		
		for(int i=0;i<10;i++){
			System.err.println("age "+i+" is:"+age);
		}
	}
	
	public synchronized void printAge(int age) {
		//synchronized(this){
			while (true){
				System.out.println(age+"xxxxxxxxxxxxxxxxxxx");
				try{
					Thread.sleep(5000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
			}
		//}
			
	}

	public void run() {
		printAge(age);
	}
}

class Test {
	public static void main(String args[]) {
		Student s1 = new Student(1);
		s1.start();
		try{
		Thread.sleep(5000);//主线程休眠,然s1线程执行
			}catch (InterruptedException e) {
						e.printStackTrace();
					}
		s1.printAge();
	}
}
liuhu_pp 2014-04-04
  • 打赏
  • 举报
回复
引用 21 楼 u010570779 的回复:
age 0 is:1 age 1 is:11xxxxxxxxxxxxxxxxxxx age 2 is:1 age 3 is:1 age 4 is:1 age 5 is:1 age 6 is:1 age 7 is:1 age 8 is:1 age 9 is:1 1xxxxxxxxxxxxxxxxxxx
。。。。。。
u010570779 2014-04-04
  • 打赏
  • 举报
回复
age 0 is:1 age 1 is:11xxxxxxxxxxxxxxxxxxx age 2 is:1 age 3 is:1 age 4 is:1 age 5 is:1 age 6 is:1 age 7 is:1 age 8 is:1 age 9 is:1 1xxxxxxxxxxxxxxxxxxx
liuhu0208 2014-04-04
  • 打赏
  • 举报
回复
引用 19 楼 fanslate 的回复:
正常情况下应该是Student线程start之后没那么快准备好,主线程不等继续走,所以主线程的一点代码很快执行完了,然后才轮到Student线程。所以一般做这种测试在启动线程之后都需要再Thread.sleep()一下等线程准备好。 出来的第一行结果实在没见过,不会是和上次的结果搞串了吧..
没串啊 上一次结果都清空了的 而且设置一个静态变量count 很清楚就能看出不是上一次的运行结果
byourfan 2014-04-04
  • 打赏
  • 举报
回复
正常情况下应该是Student线程start之后没那么快准备好,主线程不等继续走,所以主线程的一点代码很快执行完了,然后才轮到Student线程。所以一般做这种测试在启动线程之后都需要再Thread.sleep()一下等线程准备好。 出来的第一行结果实在没见过,不会是和上次的结果搞串了吧..
liuhu_pp 2014-04-04
  • 打赏
  • 举报
回复
引用 15 楼 momoyssy 的回复:
[quote=引用 14 楼 u014157407 的回复:]
[quote=引用 13 楼 momoyssy 的回复:]
做了几次试验,都没有出现过楼主说的那种情况。
s1.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
s1.printAge();
就算是这样改了,也没出现。


奇怪了 我跑十次有六次出现这样的情况

[/quote]
这个结果是正常的。
线程的状态有几种
创建,可运行,运行,睡眠(等待),死亡
s1.start();这个是可运行状态,但是程序不一定在运行,只是先挂起。由于这里时间特别短,所以CPU就有权先运s1.printAge();所以结果就会是你一开始的那种情况。如果照我改的去运行,时间片长了,就会先运行s1.start();这就不会有你说的那种情况了。[/quote]

不好意思啊 截错图了 是这个结果 不理解

liuhu_pp 2014-04-04
  • 打赏
  • 举报
回复
引用 16 楼 jutem 的回复:
恩,如果说sleep()不会释放对象所的话,s1.printAge()是死循环,楼主的第一个输出就是1XXXXXX,说明s1.printAge()已经拿到锁了,那又怎么会再输出age 1:is1呢。 不过我试了一下楼主的程序,好像就第一次出现输出1XXX后再输出age 1:is1(也可能看走眼了)。之后又试了好多次,都是在age 9:is1之后再输出1XXX的
sleep()是不会释放对象的锁 也不会让出cpu 但是我试过很多次 很多情况下都是输出1XXX 然后让出对象锁 另外一个线程执行结束 再继续执行原线程 不知道为什么
jutem 2014-04-04
  • 打赏
  • 举报
回复
恩,如果说sleep()不会释放对象所的话,s1.printAge()是死循环,楼主的第一个输出就是1XXXXXX,说明s1.printAge()已经拿到锁了,那又怎么会再输出age 1:is1呢。 不过我试了一下楼主的程序,好像就第一次出现输出1XXX后再输出age 1:is1(也可能看走眼了)。之后又试了好多次,都是在age 9:is1之后再输出1XXX的
momoyssy 2014-04-04
  • 打赏
  • 举报
回复
引用 14 楼 u014157407 的回复:
[quote=引用 13 楼 momoyssy 的回复:] 做了几次试验,都没有出现过楼主说的那种情况。 s1.start(); try { Thread.sleep(5000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } s1.printAge(); 就算是这样改了,也没出现。
奇怪了 我跑十次有六次出现这样的情况 [/quote] 这个结果是正常的。 线程的状态有几种 创建,可运行,运行,睡眠(等待),死亡 s1.start();这个是可运行状态,但是程序不一定在运行,只是先挂起。由于这里时间特别短,所以CPU就有权先运s1.printAge();所以结果就会是你一开始的那种情况。如果照我改的去运行,时间片长了,就会先运行s1.start();这就不会有你说的那种情况了。
liuhu_pp 2014-04-04
  • 打赏
  • 举报
回复
引用 13 楼 momoyssy 的回复:
做了几次试验,都没有出现过楼主说的那种情况。
s1.start();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
s1.printAge();
就算是这样改了,也没出现。


奇怪了 我跑十次有六次出现这样的情况

momoyssy 2014-04-04
  • 打赏
  • 举报
回复
做了几次试验,都没有出现过楼主说的那种情况。 s1.start(); try { Thread.sleep(5000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } s1.printAge(); 就算是这样改了,也没出现。
liuhu_pp 2014-04-04
  • 打赏
  • 举报
回复
引用 9 楼 gotta521 的回复:
结果对啊。CPU在一个时间内只运行一个任务。。。这两个方法交替获得CPU执行
同一个对象 不同线程运行不同的synchronized方法应该是互斥的吧 这是是对象锁啊 同一个对象
加载更多回复(11)

62,621

社区成员

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

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