Thread种/java多线程(理论篇)

Thread类/java多线程(理论篇)
//线程介绍
public class ThreadText {
/*
	 科普:
	 	什么是线程
	 	
		 传统的程序设计语言同一时刻只能执行单任务操作,效率非常低,如果网络程序在接收
		数据时发生阻塞,只能等到程序接收数据之后才能继续运行。随着 Internet 的飞速发展,这
		种单任务运行的状况越来越不被接受。如果网络接收数据阻塞,后台服务程序就会一直处于
		等待状态而不能继续任何操作。这种阻塞情况经常发生,这时的 CPU 资源完全处于闲置状态。
		     多线程实现后台服务程序可以同时处理多个任务,并不发生阻塞现象。多线程是 Java 语
		言的一个很重要的特征。多线程程序设计最大的特点就是能够提高程序执行效率和处理速度。
		Java 程序可同时并行运行多个相对独立的线程。例如创建一个线程来接收数据,另一个线程
		发送数据,既使发送线程在接收数据时被阻塞,接受数据线程仍然可以运行。
		     线程(Thread)是控制线程(Thread of Control)的缩写,它是具有一定顺序的指令序列
		(即所编写的程序代码)、存放方法中定义局部变量的栈和一些共享数据。线程是相互独立
		的,每个方法的局部变量和其他线程的局部变量是分开的,因此,任何线程都不能访问除自
		身之外的其他线程的局部变量。如果两个线程同时访问同一个方法,那每个线程将各自得到
		此方法的一个拷贝。
		     Java 提供的多线程机制使一个程序可同时执行多个任务。线程有时也被称为小进程,它
		是从一个大进程里分离出来的小的独立的线程。由于实现了多线程技术,Java 显得更健壮。
		多线程带来的好处是更好的交互性能和实时控制性能。多线程是强大而灵巧的编程工具,但
		要用好它却不是件容易的事。在多线程编程中,每个线程都通过代码实现线程的行为,并将
		数据供给代码操作。编码和数据有时是相当独立的,可分别向线程提供。多个线程可以同时
		处理同一代码和同一数据,不同的线程也可以处理各自不同的编码和数据。

线程周期:
		一个线程有 4 种状态,任何一个线程都处于这 4 种状态中的一种状态。
		
		1.创建(new)状态:
		调用 new 方法产生一个线程对象后、调用 start 方法前所处的状
		态。线程对象虽然已经创建,但还没有调用 start 方法启动,因此无法执行。当线程
		处于创建状态时,线程对象可以调用 start 方法进入启动状态,也可以调用 stop 方法
		进入停止状态。
		2.可运行(runnable)状态:
		当线程对象执行 start()方法后,线程就转到可运行状态。
		进入此状态只是说明线程对象具有了可以运行的条件,但线程并不一定处于运行状
		态。因为在单处理器系统中运行多线程程序时,一个时间点只有一个线程运行,系
		统通过调度机制实现宏观意义上的运行线程共享处理器。因此一个线程是否在运行,
		除了线程必须处于 Runnable 状态之外,还取决于优先级和调度。
		3.不可运行(non Runnable)状态:
		线程处于不可运行状态是由于线程被挂起或者发
		生阻塞,例如对一个线程调用 wait()函数后,它就可能进入阻塞状态;调用线程的
		notify 或 notifyAll 方法后它才能再次回到可执行状态。
		4.退出(done)状态:
		一个线程可以从任何一个状态中调用 stop 方法进入退出状态。
		线程一旦进入退出状态就不存在了,不能再返回到其他的状态。除此之外,如果线
		程执行完 run 方法,也会自动进入退出状态。
 	
 方法:
 			    start(): 开始执行一个线程
 			     stop(): 结束执行一个线程
 			sleep(long): 暂停一段时间,这个时间为给定的毫秒
 		sleep(long,int): 暂停一段时间,这个时间为毫秒加纳秒
 			  suspend(): 挂起执行
 			   resume(): 恢复执行
 			    yield(): 明确放弃执行
 			     wait(): 进入阻塞状态
 			   notify(): 阻塞状态解除
 			   
 		注意:stop()、suspend()和 resume()方法现在已经不提倡使用,这些方法在虚拟机中可能
		引起“死锁”现象。suspend()和 resume()方法的替代方法是 wait()和 sleep()。线程的退出通常
		采用自然终止的方法,建议不要人工调用 stop()方法。
 
 
		 线程在调用 start()方法之后,
		系统会自动调用 run()方法。与一般方法调用不同的地方在于一般方法调用另外一个方法后,
		必须等被调用的方法执行完毕才能返回,而线程的 start()方法被调用之后,系统会得知线程准
		备完毕并且可以执行 run()方法,start()方法就返回了,start()方法不会等待 run()方法执行完毕。


1.线程进入可执行状态
 
 	(1)其他线程调用 notify()或者 notifyAll()方法,唤起处于不可执行状态的线程。
 	     notify 仅仅唤醒一个线程并允许它获得锁,notifyAll 唤醒所有等待这个对象的线程,并
		  允许它们获得锁。
		  
	(2)线程调用 sleep(millis)方法,millis 毫秒之后线程会进入可执行状态。
		sleep(long millis)
	           在 millis 毫秒数内让当前正在执行的线程进入休眠状态,等到时间过后,该线程会自动
		苏醒并继续执行。sleep 方法的精确度受到系统计数器的影响。
		sleep(long millis, int nanos) 
		在毫秒数(millis)加纳秒数(nanos)内让当前正在执行的线程进入休眠状态,此操作
		的精确度也受到系统计数器的影响。
		
2.线程进入不可执行状态

	(1)线程自动调用 wait()方法,等待某种条件的发生。
		当其他线程调用 notify()方法或 notifyAl()方法后,处于等待状态的线程获得锁之后才会
		被唤醒,然后该线程一直等待重新获得对象锁才继续运行。
		
	(2)线程调用 sleep()方法进入不可执行状态,在一定时间后会进入可执行状态。
	
	(3)线程等待 I/O 操作的完成。
	
	
isAlive()方法用来判断一个线程是否存活。当线程处于可执行状态或不可执行状态时,
isAlive()方法返回 true;当线程处于创建状态或退出状态时,则返回 false。

	判断第一个线程是否已经终止,如果终止再来调用第二个线程。这里提供两种方法。
	 	第一种是不断查询第一个线程是否已经终止,如果没有,则让主线程睡眠一直到它终止
	 	线程 1.start();
		while(线程 1.isAlive())
		{
		     Thread.sleep(休眠时间);
		}
		
		第二种是利用 join()方法。
		join(long millis) 等待该线程终止的时间最长为毫秒(millis),超时为 0 意味着要一直等下去。
		join(long millis,int nanos) 等待该线程终止的时间最长为毫秒(millis)加纳秒(nanos)。
		join() 等待该线程终止。

	
getPriority() 获得当前线程的优先级。
xx.setPriority(1);  //设置 myThread1 的优先级 1
xx.setPriority(10); //设置 myThread2 的优先级 10
	
		设 置 线 程 的 优 先 级 为 newPriority 。 newPriority 的 值 必 须 在 MIN_PRIORITY 到
		MAX_PRIORITY 范围内,通常它们的值分别是 1 和 10。目前 Windows 系统只支持 3 个级别的优
		先级,它们分别是 Thread.MAX_PRIORITY、Thread.MIN_PRIORITY 和 Thread.NORM_PRIORITY。


线程同步:
		当把一语句块声明为 synchornized,在同一时间,它的访问线程之一才能执行该语句块。
		用关键字 synchonized 可将方法声明为同步
		
			科普:
				在一个类中,用关键字 synchonized 声明的方法为同步方法。Java 有一个专门负责管理
				线程对象中同步方法访问的工具——同步模型监视器,它的原理是为每个具有同步代码的对
				象准备惟一的一把“锁”。当多个线程访问对象时,只有取得锁的线程才能进入同步方法,
				其他访问共享对象的线程停留在对象中等待,如果获得锁的线程调用 wait 方法放弃锁,那么
				其他等待获得锁的线程将有机会获得锁。当某一个等待线程取得锁,它将执行同步方法,而
				其他没有取得锁的线程仍然继续等待获得锁。
		
			语法:
				class 类名{
				     public synchonized 类型名称 方法名称(){
				            //......
				     }
				}
			或:
				public void method()
				{
				  Object obj= new Object(); //创建局部 Object 类型对象 obj
				  synchornized(obj) //同步块
				  {
				       //……………
				  }
				}
		
		Java 程序中线程之间通过消息实现相互通信,wait()、notify()及 notifyAll()方法可完成线
		程间的消息传递。例如,一个对象包含一个 synchonized 同步方法,同一时刻只能有一个获得
		锁的线程访问该对象中的同步方法,其他线程被阻塞在对象中等待获得锁。当线程调用 wait()
		方法可使该线程进入阻塞状态,其他线程调用 notify()或 notifyAll()方法可以唤醒该线程。


死锁:
		为了保证数据安全使用 synchronized 同步机制,当线程进入堵塞状态(不
		可运行状态和等待状态)时,其他线程无法访问那个加锁对象(除非同步锁被解除),所以
		一个线程会一直处于等待另一个对象的状态,而另一个对象又会处于等待下一个对象的状态,
		以此类推,这个线程“等待”状态链会发生很糟糕的情形,即封闭环状态(也就是说最后那
		个对象在等待第一个对象的锁)。此时,所有的线程都陷入毫无止境的等待状态中,无法继
		续运行,这种情况就称为“死锁”。虽然这种情况发生的概率很小,一旦出现,程序的调试
		变得困难而且查错也是一件很麻烦的事情。
		
		Java 语言本身并没有提供防止死锁的具体方法,但是在具体程序设计时必须要谨慎,以防止出现死锁现象。
	
通常在程序设计中应注意:
	不要使用 stop()、suspend()、resume()以及 destroy()方法。
	stop()方法不安全,它会解除由该线程获得的所有对象锁,而且可能使对象处于不连贯状
	态,如果其他线程此时访问对象,而导致的错误很难检查出来。suspend()/resume ()方法也极
	不安全,调用 suspend()方法时,线程会停下来,但是该线程并没有放弃对象的锁,导致其他
	线程并不能获得对象锁。调用 destroy()会强制终止线程,但是该线程也不会释放对象锁。

 */
}