您的位置:首页 > 编程语言 > Java开发

java多线程之入门

2015-01-03 16:19 148 查看
转载请注明出处
http://blog.csdn.net/pony_maggie/article/details/42364105
作者:小马

先看一个不使用多线程造成困扰的简单示例,如下图:



程序打算实现这样的效果,点击start,文本框里开始显示不断递增的数字,直到点击Toggle按钮,停止显示。但是实际情况是,点击start发现程序出现"死机"现象,不再响应其它事件,点击Toggle按钮是没有作用的。下面从代码上来分析一下原因,这是一个基于applet的小代码:

public class Counter1 extends JApplet
{

	private int count = 0;
	private JButton startButton = new JButton("Start");
	private JButton onoffButton = new JButton("Toggle");
	private JTextField t = new JTextField(10);
	private boolean runFlag = true;
	
	public void init()
	{
		Container cp = getContentPane();
		cp.setLayout(new FlowLayout());
		cp.add(t);
		
		startButton.addActionListener(new StartL());
		cp.add(startButton);
		
		onoffButton.addActionListener(new OnOffL());
		cp.add(onoffButton);
		
		
	}
	
	
	public void go()
	{
		while(true)
		{
			try 
			{
				Thread.sleep(100);
			} 
			catch (InterruptedException e) 
			{
				
				
				// TODO: handle exception
				System.err.println("Interrupted");
			}
			
			if(runFlag)
			{
				t.setText(Integer.toString(count++));
			}
		}
	}
	
	class StartL implements ActionListener
	{
		//点击start按钮触发go函数执行。
		public void actionPerformed(ActionEvent e)
		{
			go();
		}
	}
	
	class OnOffL implements ActionListener
	{
		public void actionPerformed(ActionEvent e)
		{
			runFlag = !runFlag;
		}
	}
	
	public static void main(String[] args)
	{
		Console.run(new Counter1(), 300, 100);
	}
	
	
	
}


go函数是整个程序的关键,这个是基本applet代码的执行函数,可以看到go函数里有sleep,可能会误以为点击其它按钮应该可以响应, 在sleep阶段是“留给”其它事件的机会。其实不是这样。因为本身是在一个线程里(main主线程), 函数有个while 无限循环,所以go函数出不来,那么actionPerformed函数也就出不来,所以也就无法响应其它的事件。单线程的劣势就在这里,一个动作完不成,另一个动作当然也就轮不到。

另外,注意到sleep有可能产生InterruptedException这样的异常,这个是当前的线程被另一个线程中断时抛出的,是一个检查异常(checked exception),所以要处理。可能会有疑问,线程正在睡觉,还怎么能抛出异常呢? 网上有人这样理解,“它正在睡觉,突然被吵醒了,很生气就抛出了一个异常。” 不过我倒是觉得,只有当前线程sleep了才可能抛出异常,如果一直工作状态,是无法抛出的。

事实上,每个线程都有一个与之对应的状态,标记线程的中断状态,默认当然是false,当另一个线程通过调用 Thread.interrupt() 中断一个线程时,会出现以下两种情况之一。如果那个线程在执行一个低级可中断阻塞方法,例如 Thread.sleep()、 Thread.join() 或 Object.wait(),那么它将取消阻塞并抛出 InterruptedException当然有些方法并没有这么友好,收到中断通知就马上中断,还可能会忽略。

那么如何利用多线程解决上述程序的假死问题呢? 不着急改程序,先用一个简单的示例学习一下多线程,java里处理多线程的方法很多,继承Thread是最简单的方法,

public class SimpleThread extends Thread
{

	public int countDown = 5;
	public static int threadCount = 0;
	public int threadNumber = ++threadCount;
	
	public SimpleThread()
	{
		System.out.println("making" + threadNumber);
	}


这个示例创建5个线程实例, 每个实际有一个内部的计数器,初始值是5,线程每得到一个运行的机会(run),这个计数器会减1,减到0该线程就会停止。看一下它的main函数,

public static void main(String[] args) 
	{
		for(int i = 0; i < 5; i++)
			new SimpleThread().start();
		System.out.println("all threads start");

	}


当我们启动一个java程序的时候,就有一个java.exe的进程,这个进程至少存在一个线程,也就是当前运行main的主线程,然后我们就可以通过new Thread这种方式去创建新的线程并启动它们。启动线程用的是start。

public void run()
	{
		while(true)
		{
			System.out.println("thread "+threadNumber + "(" + countDown + ")");
			if(--countDown == 0) return;//run里有个退出机制来释放CPU
		}
	}


run是最重要的方法,这个方法是你要继承实现的,可以理解为一个线程的线程体,是这个线程实际要做的事情。要记得你的程序中不要直接调用run方法,不然它就是直接在你的主线程里,并没有起到多线程的作用。

运行结果如下:

making1
making2
thread 1(5)
thread 1(4)
thread 1(3)
making3
thread 1(2)
thread 2(5)
thread 1(1)
thread 2(4)
making4
thread 2(3)
thread 3(5)
thread 2(2)
making5
thread 3(4)
thread 4(5)
thread 2(1)
thread 3(3)
all threads start
thread 4(4)
thread 5(5)
thread 3(2)
thread 4(3)
thread 5(4)
thread 3(1)
thread 4(2)
thread 5(3)
thread 4(1)
thread 5(2)
thread 5(1)<span style="color: rgb(0, 153, 0);">
</span>


运行结果说明了两点,一是多个线程之间确实在轮换执行,二是线程之间的运行顺序跟创建的顺序并没有关系。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: