JAVA 多线程+同步的疑问,请大侠指路

SRCIsGrowing 2013-05-14 03:33:16


public class test {

public static int data=0; // share data

public static boolean flag= false; // control run()

public static void main(String[] args) throws InterruptedException{
TestSync ts = new TestSync(false);

Thread t10= new Thread(ts);
Thread t11= new Thread(ts);
Thread t20 = new Thread(ts);
t10.start();
Thread.sleep(500); // 使得t10线程启动
t11.start();
Thread.sleep(500);// 使得t11线程启动

test.flag=true;
t20.start();
}
}

class TestSync implements Runnable{

boolean flag=false; // control test1


public TestSync(boolean flag) {
super();
this.flag = flag;
}

public synchronized void test1() throws InterruptedException{
if(this.flag==false)
{
test.data= 100;
Thread.sleep(2000);
System.out.println(test.data+" test1");
this.flag= true;
}
else
{
test.data= 200;
//Thread.sleep(2000);
System.out.println(test.data);
this.flag= false;
}
}

public synchronized void test2() throws InterruptedException{

test.data = 500;
System.out.println(test.data+" test2");
}


@Override
public void run() {
// TODO Auto-generated method stub
try {
if(test.flag==false){
test1();
}else{
test2();
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}
}


我预计的顺序是t10 --> t11 --> t20
实际执行顺序 t10 --> t20 --> t11
1. 有哪位大侠了解,这是为什么啊?
小白想了半天,无法解释!!!

PS:
如果将test2的synchronized关键字去掉,
执行顺序
t20--> t10-->t11
这个应该没有问题

2. 求助大侠,帮小白理解其原理,谢谢。
3. 如果有线程执行test1()方法,我希望data 这个变量在test2()方法中无法update,这个怎么实现啊?
三个问题。。。
...全文
291 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
xiajunsongfan 2013-05-15
  • 打赏
  • 举报
回复
引用 8 楼 sjkzc3 的回复:
[quote=引用 5 楼 xiajunsongfang 的回复:]

if(this.flag==false)
        {
            test.data= 100;
            Thread.sleep(2000);
            System.out.println(test.data+" test1");
             this.flag= true;
        }
问题一:t10最先运行,500毫秒后t11开始运行并等待test1()的锁释放,注意是2000毫秒后test1()才释放,在t11等待的过程中t20开始运行并且也等待t10 释放test1()的锁。所以t11,t20就会进入等待队列ContentionList,但由于ContentionList是后进先出,所以t20先运行。
终于有突破了。 能否推荐一下关于这类问题的资料。 多谢![/quote] 建议多看一下深入java虚拟机之类的书对你会有帮助。
SRCIsGrowing 2013-05-15
  • 打赏
  • 举报
回复
引用 10 楼 zhaogang 的回复:
昏啊~!按错键,将回复提交了。 继续未完的话 虽然公平锁理论上会比非公平锁效率高,但实际使用中,当锁竞争激烈时,公平锁会影响程序的吞吐量。
整个例子看看啊~~~ 多谢!
zhaogang 2013-05-15
  • 打赏
  • 举报
回复
引用 11 楼 sjkzc3 的回复:
[quote=引用 10 楼 zhaogang 的回复:] 昏啊~!按错键,将回复提交了。 继续未完的话 虽然公平锁理论上会比非公平锁效率高,但实际使用中,当锁竞争激烈时,公平锁会影响程序的吞吐量。
整个例子看看啊~~~ 多谢![/quote]
public class Main{
	public static void main(String[] args)  throws InterruptedException {
		Fair fair = new Fair(true);//true 用使用公平策略  false 使用非公平策略
		for(int i=1; i< 50; i++){
			new FairTestThread(fair, (new Random().nextInt(2) + 1)).start();
		}//for
	}
}

public class Fair {
	private final ReentrantLock lock;

	public Fair(boolean fair){
		lock = new ReentrantLock(fair);
	}
	
	//模拟一个较耗时的task
	public void testFair1() throws InterruptedException{
		lock.lock();
		try{
			for(int i=0; i<100000; i++){}
		}finally{
			lock.unlock();
		}//finally
	}

	//模拟一个较快完成的task
	public void testFair2() throws InterruptedException{
		lock.lock();
		try{
			for(int i=0; i<1000; i++){}
			
		}finally{
			lock.unlock();
		}//finally
	}	
}

public class FairTestThread extends Thread {
	private Fair fair;
	private int type = 1;
	
	public FairTestThread(Fair fair, int type) {
		this.fair = fair;
		this.type = type;
	}

	public void run() {
		long start;
		try {
			while (!Thread.currentThread().isInterrupted()) {
				start = System.nanoTime();
				if(type == 1)
					fair.testFair1();
				else
					fair.testFair2();
				System.out.println((System.nanoTime() - start));
			}// while
		} catch (InterruptedException e) {
			e.printStackTrace();
			Thread.currentThread().interrupt();
		}//catch
	}
}
zhaogang 2013-05-14
  • 打赏
  • 举报
回复
昏啊~!按错键,将回复提交了。 继续未完的话 虽然公平锁理论上会比非公平锁效率高,但实际使用中,当锁竞争激烈时,公平锁会影响程序的吞吐量。
zhaogang 2013-05-14
  • 打赏
  • 举报
回复
引用 6 楼 andycpp 的回复:
[quote=引用 5 楼 xiajunsongfang 的回复:] 但由于ContentionList是后进先出,所以t20先运行。。
等待队列里的线程,竟然是后进先出?竟然不是随机选择? 上网搜了一下,似乎确实是这样,太让我惊讶了,我一直以为线程对锁的竞争是公平的,真无语。[/quote] Java的锁分内置锁(synchronized)和显式锁(java.util.locks.ReentrantLock),内置锁使用的是非公平策略,而显式锁默认使用的是非公平策略,当然也可以在创建显式锁对象时设置其为公平策略。但公平锁会影响
SRCIsGrowing 2013-05-14
  • 打赏
  • 举报
回复
引用 5 楼 xiajunsongfang 的回复:

if(this.flag==false)
        {
            test.data= 100;
            Thread.sleep(2000);
            System.out.println(test.data+" test1");
             this.flag= true;
        }
问题一:t10最先运行,500毫秒后t11开始运行并等待test1()的锁释放,注意是2000毫秒后test1()才释放,在t11等待的过程中t20开始运行并且也等待t10 释放test1()的锁。所以t11,t20就会进入等待队列ContentionList,但由于ContentionList是后进先出,所以t20先运行。
终于有突破了。 能否推荐一下关于这类问题的资料。 多谢!
andycpp 2013-05-14
  • 打赏
  • 举报
回复
引用 5 楼 xiajunsongfang 的回复:
但由于ContentionList是后进先出,所以t20先运行。
高手,针对这个问题,我很感兴趣,我专门开贴进行提问,有劳您大驾,给解答一下 http://bbs.csdn.net/topics/390458387
andycpp 2013-05-14
  • 打赏
  • 举报
回复
引用 5 楼 xiajunsongfang 的回复:
但由于ContentionList是后进先出,所以t20先运行。。
等待队列里的线程,竟然是后进先出?竟然不是随机选择? 上网搜了一下,似乎确实是这样,太让我惊讶了,我一直以为线程对锁的竞争是公平的,真无语。
xiajunsongfan 2013-05-14
  • 打赏
  • 举报
回复

if(this.flag==false)
        {
            test.data= 100;
            Thread.sleep(2000);
            System.out.println(test.data+" test1");
             this.flag= true;
        }
问题一:t10最先运行,500毫秒后t11开始运行并等待test1()的锁释放,注意是2000毫秒后test1()才释放,在t11等待的过程中t20开始运行并且也等待t10 释放test1()的锁。所以t11,t20就会进入等待队列ContentionList,但由于ContentionList是后进先出,所以t20先运行。
SRCIsGrowing 2013-05-14
  • 打赏
  • 举报
回复
引用 2 楼 zhaogang 的回复:
第一个问题: start()方法只是代表一个线程进入了就绪状态,并不代表它就会执行。所以你每次执行的顺序都不一定一样。 第二个问题: 问题太含糊。 第三个问题: 你这里
public synchronized  void test1()
的写法基本等于 synchronized(this),也就是调用test1()或test2()方法时等于给当前TestSync对象加了同步锁,所以每次都只有一个线程根据判断能调用到test1()或test2()
可能我的表述有点不清楚。 我在main()函数中sleep()方法是故意加上去的,请看上面的回帖。
SRCIsGrowing 2013-05-14
  • 打赏
  • 举报
回复
引用 1 楼 fsh2008 的回复:
我感觉你这样测试是不对的,以下是我电脑的测试情况: 如果sleep足够长,那么结果是: 100 test1 200 500 test2 你试试改成5000。 如果sleep比较短(500),那么结果: 100 test1 500 test2 200 如果没有sleep,那么结果: 100 test1 500 test2 500 test2 个人认为,要想测试多线程+同步,最好使用线程池,然后给每个线程加上线程名称在打印的时候打印出来。
我写这个测试程序,是为了加深对synchronize的理解。 我在main()上加Sleep()方法是为了让t10,t11启动起来; 当t10, t11调用的是test1()方法,t10,t11是同步的; t20调用test2()方法,在t10,t11在未改变test.data的值之前,已经将test.data修改了。。。 test1(), test2()同样使用synchronized关键字,锁定的是TestSync对象;我调用的是顺序是t10,t11,t20, 但是实际运行下来则是t10,t20,t11, 这样让我很费解。 synchronized是怎样将锁传给下一个执行单元呢? 如果main函数,没有sleep()方法,首先执行的是test2()方法。 我调用的顺序是t10,t11,t20, 同时test1(),test2()都使用sync关键字,但是执行的顺序是不同的?为什么呢?
zhaogang 2013-05-14
  • 打赏
  • 举报
回复
第一个问题: start()方法只是代表一个线程进入了就绪状态,并不代表它就会执行。所以你每次执行的顺序都不一定一样。 第二个问题: 问题太含糊。 第三个问题: 你这里
public synchronized  void test1()
的写法基本等于 synchronized(this),也就是调用test1()或test2()方法时等于给当前TestSync对象加了同步锁,所以每次都只有一个线程根据判断能调用到test1()或test2()
fsh2008 2013-05-14
  • 打赏
  • 举报
回复
我感觉你这样测试是不对的,以下是我电脑的测试情况: 如果sleep足够长,那么结果是: 100 test1 200 500 test2 你试试改成5000。 如果sleep比较短(500),那么结果: 100 test1 500 test2 200 如果没有sleep,那么结果: 100 test1 500 test2 500 test2 个人认为,要想测试多线程+同步,最好使用线程池,然后给每个线程加上线程名称在打印的时候打印出来。

62,614

社区成员

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

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