`
gegewuqin9
  • 浏览: 28896 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

终于完成了一个小小的java多线程

阅读更多
对多线程方面一直只限概念,感觉用到的不多,所以没深入去了解。但发现面试时却经常会问到,于是便想了一个简单的题目,亲自实践下。题目如下:
由2个线程控制主线程的一个变量,一个调用加的方法,一个调用减的方法,要求变量值不能小于0(如果等于0,则减的方法必须等待)。一个典型的有货才卖的类型 ,由于新手,所以捣鼓了好久,终于成功了,下面是代码,不知道有什么能改进的。
*以下是经过修改的代码:

public class ThreadTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		ThreadTest t = new ThreadTest();
		Thread t3 = new Thread(new MinusThread(t));
		Thread t2 = new Thread(new MinusThread(t));
		Thread t1 = new Thread(new AddThread(t));
		t1.start();
		t2.start();
		t3.start();
	}
	
	
	static int num = 0;
	public synchronized void add() {
		while(num >= 10)
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		num++;
		System.out.println("num+1="+num);
	}
	
	public synchronized void minus() {
		while(num <= 0)
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		num--;
		System.out.println("num-1="+num);
	}
	
	public synchronized void change(int type) {
		if(type==0) {
			num++;
			System.out.println("num+1="+num);
		} else {
			while(num <= 0)
				try {
					this.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			num--;
			System.out.println("num-1="+num);
		}
	}
}

class AddThread implements Runnable {
	ThreadTest t;
	public AddThread (ThreadTest t) {
		this.t = t;
	}
	public void run() {
		int i = 100;
		while(i-->0) {
			synchronized (t) {
				t.add();
				t.notify();
			}
		}
	}
}

class MinusThread implements Runnable {
	ThreadTest t;
	public MinusThread (ThreadTest t) {
		this.t = t;
	}
	public void run() {
		int i = 100;
		while(i-->0) {
			synchronized (t) {
				t.minus();
				t.notify();
			}
		}
	}
}
6
9
分享到:
评论
22 楼 mengqingyu 2013-06-21  
可以看看这个 http://mengqingyu.iteye.com/blog/1840675
21 楼 wuchsh2013 2013-06-20  
太复杂,看不懂
20 楼 406657836 2013-06-20  
chen3975 写道
gegewuqin9 写道
chen3975 写道

你写的和我的差不多,就是sysout这个换了地方,但你把这个写在外面是不对的,因为getSum()时sum的值可能已经被另一个线程改变了,我测试了一下很乱..

我觉的和你的不一样,虽然都是有两个线程和一个主线程.但是我的同步代码是放在主线程类中的,而你的和我的不一样,显的很乱.

显然,更喜欢你的这个风格,看起来很清晰,面向对象的思想也有了。不错!
19 楼 chen3975 2013-06-20  
gegewuqin9 写道
chen3975 写道

你写的和我的差不多,就是sysout这个换了地方,但你把这个写在外面是不对的,因为getSum()时sum的值可能已经被另一个线程改变了,我测试了一下很乱..

我觉的和你的不一样,虽然都是有两个线程和一个主线程.但是我的同步代码是放在主线程类中的,而你的和我的不一样,显的很乱.
18 楼 chen3975 2013-06-20  
gegewuqin9 写道
chen3975 写道

你写的和我的差不多,就是sysout这个换了地方,但你把这个写在外面是不对的,因为getSum()时sum的值可能已经被另一个线程改变了,我测试了一下很乱..


放哪里都一样,都可能被别的线程修改访问,因为minus和add不是互斥操作.如果他们是互斥操作的话放在各自的方法里就保证获得sum值是当时的
17 楼 406657836 2013-06-20  
gegewuqin9 写道
406657836 写道

大神,可是我测试的时候是可以实现的,是不是取巧了··· 
我现在把notify()放到加的线程里激活了,你能帮忙看看怎么样么?

嗯 你这个程序暂时可能没有什么线程安全的问题了。但是 你这个代码真的很难看,而且一点面向对象的思想都没有。还有你可以尝试启动两个减的线程,你会发现有些时候 num的值会小于0。你现在只有一个减的线程 所以不会出现。
16 楼 gegewuqin9 2013-06-20  
406657836 写道

大神,可是我测试的时候是可以实现的,是不是取巧了··· 
我现在把notify()放到加的线程里激活了,你能帮忙看看怎么样么?
15 楼 gegewuqin9 2013-06-20  
chen3975 写道

你写的和我的差不多,就是sysout这个换了地方,但你把这个写在外面是不对的,因为getSum()时sum的值可能已经被另一个线程改变了,我测试了一下很乱..
14 楼 chen3975 2013-06-20  
/**
 * 减线程
 */
public class MinusRunnable implements Runnable {
	private MinusAndAdd minusAndAdd;
	public MinusRunnable(MinusAndAdd minusAndAdd){
		this.minusAndAdd = minusAndAdd;
	}
	@Override
	public void run() {
		while(true){
			minusAndAdd.minus();
			System.out.println("minus->"+minusAndAdd.getSum());
		}
	}
}

/**
 * 加线程
 */
public class AddRunnable implements Runnable {
	private MinusAndAdd minusAndAdd;
	public AddRunnable(MinusAndAdd minusAndAdd){
		this.minusAndAdd = minusAndAdd;
	}
	@Override
	public void run() {
		while(true){
			minusAndAdd.add();
			System.out.println("add->"+minusAndAdd.getSum());
		}
	}
}
/**
 * 主线程
 */
public class MinusAndAdd {
	private int sum;
	
	public int getSum() {
		return sum;
	}

	public synchronized void minus(){
		while(sum<=0){
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		sum--;
		notifyAll();
	}
	
	public synchronized void add(){
		while(sum>3){
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		sum++;
		notifyAll();
	}
	public static void main(String[] args){
		MinusAndAdd minusAndAdd = new MinusAndAdd();
		Thread minus = new Thread(new MinusRunnable(minusAndAdd));
		Thread add = new Thread(new AddRunnable(minusAndAdd));
		minus.start();
		add.start();
	}
}
13 楼 406657836 2013-06-20  
gao_xianglong 写道
提个建议,写线程不要直接继承Thread,去实现Runnable,除了更灵活,还能实现资源共享。

回答的很牵强呵!实现Runnable的理由主要是Runnable很轻,它只需要实现run方法,而Thread还要继承过来一堆方法,一堆变量,而这些变量,方法都是后面不需要用的。所以选择实现Runnable。
至于资源 共享 没有明白你的意思。但是可以肯定的是Runnable能做到的Thread就一定能做到。
12 楼 406657836 2013-06-20  
406657836 写道
gegewuqin9 写道
406657836 写道
406657836 写道
gegewuqin9 写道
406657836 写道
程序结构太乱了。
而且notifyAll没有唤醒任何等待的线程,因为就没有线程等待。
不知道楼主理解notify和wait么?他们是需要获得同一把锁才能等待唤醒的。否则是会抛异常的。
楼主应该先把程序结构,然后再重新设计下线程。虽然是学习学习,但是要有个好习惯。
加油!

去掉notifyAll试了下,确实也能达到效果。只是不太明白这是什么原理哦,当num<=0的时候,t2就处于了wait状态了,那到底是什么把它唤醒的呢?

你的t2不是被唤醒了,而是被中断了, 然后你只是自己处理了中断异常,这个程序看起来太乱了。真没法看,你重新整理下把!

t2.interrupted() 中断 并复位!

有点了解了,wait是等待,让下一个在等待的线程先运行,下一个线程运行完成后再运行。但如果是同一个方法的话就需要notify。就像我上面的change()方法.



兄弟 看来是我误导你了!你这个wait是不能自己醒的因为没有加过期时间。wait通常是可以被其他线程唤醒(需要两个线程持有同一个锁)。你这里之所以wait了其他线程执行,是因为wait会释放已经获得的锁。

还有 你的change方法的wait和notify完全用错了。wait和notify通常是在两个线程里调用的,而不是同一个。你现在的问题比你改之前更大了,罪过呀!
11 楼 406657836 2013-06-20  
gegewuqin9 写道
406657836 写道
406657836 写道
gegewuqin9 写道
406657836 写道
程序结构太乱了。
而且notifyAll没有唤醒任何等待的线程,因为就没有线程等待。
不知道楼主理解notify和wait么?他们是需要获得同一把锁才能等待唤醒的。否则是会抛异常的。
楼主应该先把程序结构,然后再重新设计下线程。虽然是学习学习,但是要有个好习惯。
加油!

去掉notifyAll试了下,确实也能达到效果。只是不太明白这是什么原理哦,当num<=0的时候,t2就处于了wait状态了,那到底是什么把它唤醒的呢?

你的t2不是被唤醒了,而是被中断了, 然后你只是自己处理了中断异常,这个程序看起来太乱了。真没法看,你重新整理下把!

t2.interrupted() 中断 并复位!

有点了解了,wait是等待,让下一个在等待的线程先运行,下一个线程运行完成后再运行。但如果是同一个方法的话就需要notify。就像我上面的change()方法.



兄弟 看来是我误导你了!你这个wait是不能自己醒的因为没有加过期时间。wait通常是可以被其他线程唤醒(需要两个线程持有同一个锁)。你这里之所以wait了其他线程执行,是因为wait会释放已经获得的锁。
10 楼 gegewuqin9 2013-06-20  
406657836 写道
406657836 写道
gegewuqin9 写道
406657836 写道
程序结构太乱了。
而且notifyAll没有唤醒任何等待的线程,因为就没有线程等待。
不知道楼主理解notify和wait么?他们是需要获得同一把锁才能等待唤醒的。否则是会抛异常的。
楼主应该先把程序结构,然后再重新设计下线程。虽然是学习学习,但是要有个好习惯。
加油!

去掉notifyAll试了下,确实也能达到效果。只是不太明白这是什么原理哦,当num<=0的时候,t2就处于了wait状态了,那到底是什么把它唤醒的呢?

你的t2不是被唤醒了,而是被中断了, 然后你只是自己处理了中断异常,这个程序看起来太乱了。真没法看,你重新整理下把!

t2.interrupted() 中断 并复位!

有点了解了,wait是等待,让下一个在等待的线程先运行,下一个线程运行完成后再运行。但如果是同一个方法的话就需要notify。就像我上面的change()方法.
9 楼 406657836 2013-06-20  
406657836 写道
gegewuqin9 写道
406657836 写道
程序结构太乱了。
而且notifyAll没有唤醒任何等待的线程,因为就没有线程等待。
不知道楼主理解notify和wait么?他们是需要获得同一把锁才能等待唤醒的。否则是会抛异常的。
楼主应该先把程序结构,然后再重新设计下线程。虽然是学习学习,但是要有个好习惯。
加油!

去掉notifyAll试了下,确实也能达到效果。只是不太明白这是什么原理哦,当num<=0的时候,t2就处于了wait状态了,那到底是什么把它唤醒的呢?

你的t2不是被唤醒了,而是被中断了, 然后你只是自己处理了中断异常,这个程序看起来太乱了。真没法看,你重新整理下把!

t2.interrupted() 中断 并复位!
8 楼 406657836 2013-06-20  
gegewuqin9 写道
406657836 写道
程序结构太乱了。
而且notifyAll没有唤醒任何等待的线程,因为就没有线程等待。
不知道楼主理解notify和wait么?他们是需要获得同一把锁才能等待唤醒的。否则是会抛异常的。
楼主应该先把程序结构,然后再重新设计下线程。虽然是学习学习,但是要有个好习惯。
加油!

去掉notifyAll试了下,确实也能达到效果。只是不太明白这是什么原理哦,当num<=0的时候,t2就处于了wait状态了,那到底是什么把它唤醒的呢?

你的t2不是被唤醒了,而是被中断了, 然后你只是自己处理了中断异常,这个程序看起来太乱了。真没法看,你重新整理下把!
7 楼 gegewuqin9 2013-06-20  
406657836 写道
程序结构太乱了。
而且notifyAll没有唤醒任何等待的线程,因为就没有线程等待。
不知道楼主理解notify和wait么?他们是需要获得同一把锁才能等待唤醒的。否则是会抛异常的。
楼主应该先把程序结构,然后再重新设计下线程。虽然是学习学习,但是要有个好习惯。
加油!

去掉notifyAll试了下,确实也能达到效果。只是不太明白这是什么原理哦,当num<=0的时候,t2就处于了wait状态了,那到底是什么把它唤醒的呢?
6 楼 gegewuqin9 2013-06-20  
hardPass 写道
你要感谢iteye的鼓励,你的程序上了首页

是的呢,iteye还是比较关心新人的,我第一次在iteye写博客~
5 楼 gegewuqin9 2013-06-20  
gao_xianglong 写道
提个建议,写线程不要直接继承Thread,去实现Runnable,除了更灵活,还能实现资源共享。

好的,多谢了,以后我会注意的。
4 楼 406657836 2013-06-19  
程序结构太乱了。
而且notifyAll没有唤醒任何等待的线程,因为就没有线程等待。
不知道楼主理解notify和wait么?他们是需要获得同一把锁才能等待唤醒的。否则是会抛异常的。
楼主应该先把程序结构,然后再重新设计下线程。虽然是学习学习,但是要有个好习惯。
加油!
3 楼 hardPass 2013-06-19  
你要感谢iteye的鼓励,你的程序上了首页

相关推荐

    Java多线程学习总结

    Java多线程是编程中的重要概念,尤其在开发高并发、高性能的应用时不可或缺。本文将深入探讨Java中的线程和进程,以及如何在Java中实现多线程。 首先,理解线程和进程的概念至关重要。线程是操作系统分配CPU时间片...

    使用Java多线程的同步机制编写应用程序.docx

    在本实验中,我们主要探讨了Java多线程的同步机制以及其在并发编程中的应用。实验目的是理解和掌握并行/并发、同步/异步的概念,并通过实现一个模拟银行账户的程序来具体应用这些概念。 首先,理解并行/并发是关键...

    学习笔记:多线程Java Socket编程示例

    总结来说,这个学习笔记提供了一个使用Java Socket编程实现多线程服务器的示例,它演示了如何利用ExecutorService创建线程池来处理并发连接,是理解Java并发编程和网络通信的一个实用案例。虽然这是一个学习笔记,但...

    多线程面试题小小总结一下

    在Java多线程编程领域,面试中经常涉及到一系列关键概念和技术。以下是对这些面试题的详细解答: 1. **Java锁机制**:Java提供多种锁机制,包括偏向锁、轻量级锁和重量级锁。偏向锁是在无竞争情况下,将锁状态设置...

    Java线程安全.docx

    Java线程安全是指在多线程并发编程中,如何确保线程安全地访问和修改共享资源的问题。Java内存模型(JMM)是Java虚拟机(JVM)定义的内存模型,旨在屏蔽底层平台的内存管理细节,提供了一个统一的内存模型规范。 ...

    关于Java线程间通信-回调.docx

    例如,`BlockingQueue`可以使一个线程在队列为空时等待,直到另一个线程将元素放入队列,这在多线程数据共享和传递中非常有效。 总的来说,回调在Java线程间通信中起到桥梁的作用,使得线程能够以非阻塞的方式互相...

    一个小小的Socket程序(附源码)

    在这个"一个小小的Socket程序(附源码)"中,我们可以看到一个简单的Socket应用程序,它可能是用C++、Java或Python等语言编写的,用于演示如何通过Socket进行数据传输。在QQ通迅中,Socket技术也扮演着关键角色,它...

    Java线程间通信的代码示例.zip

    理解并熟练掌握这些线程间通信技术,能帮助开发者在Java多线程编程中避免竞态条件、死锁等问题,提高程序的并发性能和稳定性。通过实际的代码示例,你可以更直观地学习和运用这些知识,解决实际工作中的问题。

    snmp_demo.zip_java 趣味程序_java和snmp拓扑_snmp网络拓扑_拓扑发现_网络拓扑布局

    虽然很小,它却可以完成一个简单的局域网自动发现搜索、多线程、ICMP和SNMP的ping、节点的生成、拓扑的展示、自动布局等功能。继续改巴改巴也许还有点使用价值也未可知。 如果不喜欢研究代码,就当它是一个趣味程序...

    我的毕业设计——一款小小的即时通讯系统.zip

    【标题】:“我的毕业设计——一款小小的即时通讯系统”是一个基于计算机科学与信息技术的毕业设计项目,主要目标是实现一个简单但功能完整的即时通讯(IM)系统。此系统可能包括了用户注册、登录、发送消息、接收...

    java实例100例

    9. **多线程**:Java支持多线程编程,实例可能涵盖线程的创建、同步和通信,帮助理解并发编程的概念。 10. **实用类库**:Java标准库提供了许多实用类,如Date、Random、Math等,实例会演示如何利用它们完成特定...

    java进阶提高学习教程-14锁机制.pptx

    爱思考的三酷猫刚学完多线程,它想可以把该操作间想像为是一个共享资源,所有想存取款的客户是多个线程。假如操作间有人占用,那么其他人就必须等待,直到该客户存取款操作完成,打开操作间出来为止。这与多个线程...

    一套Java写的聊天软件源码

    这套源码对于初学者来说,是一个很好的学习平台,能够深入理解Java网络编程、多线程、GUI设计等多个核心概念。通过阅读和分析源码,可以提升对Java编程和软件架构的理解,对于完成毕业设计或者提升编程技能都非常有...

    java面试题总结

    ### Java多线程 #### 7. Java中如何创建线程? 在Java中,可以通过实现Runnable接口或者继承Thread类来创建线程。通过实现Runnable接口的方式更灵活,因为这种方式并不强制要求必须继承Thread类,而且可以同时实现...

    Java官方API文档—1.6中文版和1.8中文版

    其中,`java.util.concurrent`包的工具如`ExecutorService`和`Future`接口,提高了多线程编程的效率和易用性。泛型的引入使得代码更安全,类型检查在编译时就能完成,减少了运行时错误的可能性。 1.8中文版API文档...

    中国象棋java版

    4. **多线程**: 虽然在代码示例中没有直接创建和启动线程,但实现一个实时更新的游戏通常需要线程来处理游戏逻辑和界面更新,确保两者之间的同步。 5. **MouseListener** 和 **KeyListener** 接口: `MouseListener`...

    实战Java高并发程序设计模式

    线程安全意味着在多线程环境下,一个对象的状态在被正确地同步访问时不会被破坏。Java提供了多种机制来保证线程安全,如synchronized关键字、volatile变量和Atomic类。 3. **并发设计模式**:设计模式是解决特定...

    GUI实现的小小点餐功能的实现(一)点餐系统.zip

    在本项目中,我们探讨的是一个基于GUI(图形用户界面)的小型点餐系统的实现,主要使用Java语言来开发客户端和服务端。GUI是用户与计算机系统进行交互的主要接口,它通过图形元素如按钮、文本框、菜单等提供直观的...

    Java面试笔记-基础问题篇.docx

    15. **Java不支持多继承**:一个类只能继承一个父类,但可以通过实现多个接口来达到类似的效果。 16. **Path与Classpath**:Path是系统路径,用于查找可执行文件;Classpath是Java类加载路径,用于查找.class文件。...

    Java并发面试题整理(答案).docx

    15、CountDownLatch、CyclicBarrier 和 Semaphore 的区别CountDownLatch 让一组线程等待其他线程完成操作后再继续执行,通常用于多线程的并发测试。CyclicBarrier 可以看作是一个屏障,让一组线程到达屏障时暂停,...

Global site tag (gtag.js) - Google Analytics