JAVA基础复习:涉及并发的一些基础概念


Thingking in JAVA上是这样说的:


【用并发解决的问题大体上可以分为“速度”和“设计可管理性”两种;

并发通常是提高在单处理器上的处理速度(有点违背直觉)--由于阻塞存在的原因


1、进程和线程:

进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位;

线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.一个线程就是在进程中的一个个单独的顺序控制流;

线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.

另外,一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.


2、后台线程(守护线程)


一.  java中的后台线程:


      java线程还可以分为前台线程(也称用户线程或普通线程)和后台线程(Daemon thread)


     1.  后台线程会随着主程序的结束而结束,但是前台进程则不会;或者说,只要有一个前台线程未退出,进程就不会终止。(下面的例子会充分说明这一点);


     2.  默认情况下,程序员创建的线程是用户线程;用setDaemon(true)可以设置线程为后台线程;而用isDaemon( )则可以判断一个线程是前台线程还是后台线程;


     3. jvm的垃圾回收器其实就是一个后台线程;


     4. setDaemon函数必须在start函数之前设定,否则会抛出IllegalThreadStateException异常;



import java.util.concurrent.TimeUnit;

public class MyDaemon implements Runnable {

	
	@Override
	public void run() {
		try{
			while(true){
				Thread.sleep(1000);
				System.out.println(Thread.currentThread());
				new Thread(new Runnable() {
					
					@Override
					public void run() {
						System.out.println("在后台线程里面开启新的子线程");
						
					}
				}).start();
				
			}			
		}catch (InterruptedException e) {
			e.printStackTrace();
		}
		//如果是后台线程,则finally不会被执行。因为主线程退出后,后台线程就自动退出了。
		finally{
			System.out.println("执行finally");
			
		}
		
	}
	
	public static void main(String[] args) {
		for(int i=0;i<10;i++){
			Thread daemon=new Thread(new MyDaemon());
		//后台线程在不执行finally子句的情况下就会终止其run方法。
			daemon.setDaemon(true);
			daemon.start();
		}
		
		try {
			//让主线程main()停留一会
			TimeUnit.MILLISECONDS.sleep(2000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
}
输出结果:

Thread[Thread-3,5,main]
Thread[Thread-9,5,main]
Thread[Thread-5,5,main]
Thread[Thread-1,5,main]
Thread[Thread-2,5,main]
Thread[Thread-6,5,main]
Thread[Thread-7,5,main]
在后台线程里面开启新的子线程
在后台线程里面开启新的子线程
在后台线程里面开启新的子线程
Thread[Thread-4,5,main]
Thread[Thread-0,5,main]
Thread[Thread-8,5,main]
在后台线程里面开启新的子线程
在后台线程里面开启新的子线程
在后台线程里面开启新的子线程
在后台线程里面开启新的子线程
在后台线程里面开启新的子线程
在后台线程里面开启新的子线程
在后台线程里面开启新的子线程

结论:在主线程(main())退出后,JVM强制关闭所有后台线程。而不会有任何希望出现的确认形式,如finally子句不执行。

如果MyDaemon 是用户线程,那么会一直打印下去~


3、线程状态

  创建状态、可运行状态、不可运行状态、退出状态之间的转换关系如图 所示。 

          
        通过 new第一次创建线程时,线程位于创建状态,这时不能运行线程,只能等待进一步的方法调用改变其状态。

然后,线程通过调用 start方法启动线程,并进入可执行状态,或者调用方法 stop进入退出状态。

当程序位于退出状态时,线程已经结束执行,这是线程的最后一个状态,并且不能转化到其他状态。当程序的所有线程位于退出状态时,程序会强行终止。

当线程位于可执行状态时,在一个特定的时间点上,每一个系统处理器只能运行一个线程。 此时如果线程被挂起,执行就会被中断或者进入休眠状态,那么线程将进入不可执行状态,并且不可执行状态可以通过 resume、notify等方法返回到可执行状态。表10-1列举了线程状态转换的函数。 

       线程状态转换函数: 
方法                        描述                                                          有效状态             目的状态 
start()                     开始执行一个线程                                     New                    Runnable 
stop()                     结束执行一个线程                                     New或Runnable    Done 
sleep(long)          暂停一段时间,这个时间为给定的毫秒       Runnable             NonRunnable 
sleep(long,int)     暂停片刻,可以精确到纳秒                         Runnable             NonRunnable 
suspend()            挂起执行                                                      Runnable             NonRunnable 
resume()              恢复执行                                                      NonRunnable        Runnable 
yield()                    明确放弃执行                                              Runnable             Runnable 
wait()                     进入阻塞状态                                              Runnable             NonRunnable 
notify()                   阻塞状态解除                                              NonRunnable       Runnable 
注意:stop()、suspend()和 resume()方法现在已经不提倡使用,这些方法在虚拟机中可能引起“死锁”现象。suspend()和 resume()方法的替代方法是 wait()和 sleep()。线程的退出通常采用自然终止的方法,建议不要人工调用 stop()方法。 


3.  线程状态转换 


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


2.线程进入不可执行状态 
    当以下几种情况发生时,线程进入不可执行状态。 
(1)线程自动调用 wait()方法,等待某种条件的发生。 
      public final void wait() throws InterruptedException 
     当其他线程调用 notify()方法或 notifyAl()方法后,处于等待状态的线程获得锁之后才会被唤醒,然后该线程一直等待重新获得对象锁才继续运行。 
(2)线程调用 sleep()方法进入不可执行状态,在一定时间后会进入可执行状态。 
(3)线程等待 I/O操作的完成。 

参考的是:http://blog.csdn.net/hguisu/article/details/7490616



4、线程优先级

优先级只是改变不同的线程的执行的频率,当设计多线程应用程序的时候,一定不要依赖于线程的优先级。因为线程调度优先级操作是没有保障的,只能把线程优先级作用作为一种提高程序效率的方法,但是要保证程序不依赖这种操作。


设置线程的优先级:线程默认的优先级是创建它的执行线程的优先级。可以通过setPriority(int newPriority)更改线程的优先级。例如:

        Thread t = new MyThread();
        t.setPriority(8);
        t.start();


线程优先级为1~10之间的正整数,然而,1~10之间的值是没有保证的,不同的系统存在一个映射关系,可能不能识别10个不同的值,而将这些优先级进行每两个或多个合并,变成少于10个的优先级,则两个或多个优先级的线程可能被映射为一个优先级。

线程默认优先级是5,Thread类中有三个常量,定义线程优先级范围:

static int MAX_PRIORITY 
          线程可以具有的最高优先级。
static int MIN_PRIORITY 
          线程可以具有的最低优先级。
static int NORM_PRIORITY 
          分配给线程的默认优先级。


这一节主要复习下一些基础的概念,没有涉及到什么具体内容,下一节就针对资源共享问题专门分析

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值