java线程学习笔记(二)

    一个线程的生命周期是线程的建立到线程的最终销毁的整个过程,线程的生命周期可以分为以下几个状态:新建状态,就绪状态,运行状态,阻塞状态,死亡状态。

 1.线程的新建状态

   在java中使用new关键字用于生成一个新的对象,这时的线程没有调用start方法,出现新建状态。

 2.线程的就绪状态

    当线程类使用new关键字生成了一个对象,调用该对象的start()的方法,这时该线程处于就绪状态,注意,调用了start方法后线程不会马上进入运行状态,进行执行,我们并不能控制线程何时开始执行,这时候,我们只能等到JVM虚拟机调度相关cpu资源以执行该线程。

 3.线程的运行状态

    当cpu开始执行该线程的时候,此时线程处于运行状态,线程执行的只有线程内部的唯一的执行体,就是run函数内部的内容,当run方法执行完成了,我们也就认为该线程的运行状态结束,但是我们常常需要在某种特殊的的情况下,停止线程的执行,通常这时候我有两种方式可以实现,设标示和中断线程,另外还有一种方式stop,不过该方法已经被舍弃了,因为该方法存在内容竞争,可能会引起死锁。

  以下是一个简单的例子:

public class ThreadLifeCycle {

	public static void main(String[] args) {
		
		TestThread myTestThread = new TestThread();
		myTestThread.setStop(false);
		myTestThread.start();
		try {
			
			Thread.sleep(10000);
			myTestThread.setStop(true);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}				
	}
	
	private static class TestThread extends Thread {

		private boolean isStop;

		private int testNum = 1;;
		
		public boolean isStop() {
			return isStop;
		}

		public void setStop(boolean isStop) {
			this.isStop = isStop;
		}

		public void run() {
			
			super.run();
			System.out.println("isStop-----------> " + isStop);
			while(!isStop){
				
				System.out.println("Test Number is -----> " + testNum++);
				
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}				
			}			
			System.out.println("isStop-----------> " + isStop);
						
		}
	}	
}
  在这里设置了一个标志位isStop,来决定线程什么时候结束,我们可以通过调用setStop方法来改变isStop的值,从而结束线程,通过测试发现一个现象就是运行的结果可能出现两种情况,以下是两种运行效果:

第一种:

isStop-----------> false
Test Number is -----> 1
Test Number is -----> 2
Test Number is -----> 3
Test Number is -----> 4
Test Number is -----> 5
Test Number is -----> 6
isStop-----------> true
第二种运行结果为:

isStop-----------> false
Test Number is -----> 1
Test Number is -----> 2
Test Number is -----> 3
Test Number is -----> 4
Test Number is -----> 5
isStop-----------> true
这是为什么呢,原来,通过设置标志位的方式来结束线程,子线程必须等待外部调用setStop方法,改变了标志位isStop的值后才能停止while循环,运行完run方法,从而结束该线程,而线程的执行顺序我们是不知道的,所以这里就可能出现延迟,并且延迟是无法避免的,但是我们必须想办法减少延迟,于是就有线程内的另外一个方法interrupt(),使用interrupt()也存在一定的风险,它会抛出InterruptedException,所以我们在使用时必须捕获这个异常,而通常我们捕获到这个异常后并不会做任何有意义的操作,这可以减少延迟,但是并不能消除延迟,这是因为这个方法的调用也是在其他的线程中,所以我们并不能保证两者的先后顺序。

下面的例子相关的代码:

public class ThreadLifeCycle {


	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		TestThread myTestThread = new TestThread();
		myTestThread.start();
		try {
			Thread.sleep(100);
			myTestThread.interrupt();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		
	}

	
	private static class TestThread extends Thread {
		private int testNum = 1;;
		public void run() {
			
			super.run();
			while(!isInterrupted()){
				
				System.out.println("Test Number is -----> " + testNum++);
				
			}
		}
	}
}
另外一种情况是在run方法中存在sleep,wait方法这时的处理方式如下面的例子:

public class ThreadLifeCycle {

	public static void main(String[] args) {
		
		TestThread myTestThread = new TestThread();
		myTestThread.start();
		try {
			
			
			Thread.sleep(10000);
			myTestThread.interrupt();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		
	}

	
	private static class TestThread extends Thread {
		private int testNum = 1;;
		public void run() {
			
			super.run();
			while(true){
				
				System.out.println("Test Number is -----> " + testNum++);
				
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					e.printStackTrace();
					System.out.println("sleep is interrupted ");
					return;
				}
				
			}
			
		}

	}

	
}

那么这两种方式有什么不同之处呢?

  1.假设在第二种情况下,我们调用了interrupt()方法后,捕获到Thread.sleep()的位置出现异常时不结束掉该线程的运行,该线程是不会停止下来,我们必须在Thread.sleep()出现异常时,捕获到相关的异常,并且在这里结束run方法的运行,从而使线程进入到死亡状态,这是因为在调用了sleep或者wait方法后,线程进入了阻塞状态,这时调用interrupt方法会打断该线程原有的阻塞状态,使线程醒过来,并且会抛出一个InterruptedException的异常,我们在异常的catch块结束掉run方法的运行,从而使线程进入死亡状态。

  如假如我们将第二种情况下的代码变成这个样子:

public class ThreadLifeCycle {

	public static void main(String[] args) {
		
		TestThread myTestThread = new TestThread();
		myTestThread.start();
		try {
			
			
			Thread.sleep(10000);
			myTestThread.interrupt();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
		
	}

	
	private static class TestThread extends Thread {
		private int testNum = 1;;
		public void run() {
			
			super.run();
			while(!isInterrupted()){
				
				System.out.println("Test Number is -----> " + testNum++);
				
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					e.printStackTrace();
					System.out.println("sleep is interrupted ");
//					return;
				}
				
			}
			
		}

	}

	
}
我们会发现执行的结果为:

Test Number is -----> 1
Test Number is -----> 2
Test Number is -----> 3
Test Number is -----> 4
Test Number is -----> 5
java.lang.InterruptedException: sleep interrupted
sleep is interrupted 
Test Number is -----> 6
	at java.lang.Thread.sleep(Native Method)
	at ThreadLifeCycle$TestThread.run(ThreadLifeCycle.java:31)
Test Number is -----> 7
Test Number is -----> 8
Test Number is -----> 9
Test Number is -----> 10
Test Number is -----> 11
Test Number is -----> 12
Test Number is -----> 13
Test Number is -----> 14
可以看到当我们捕获到异常后,没有退出而是继续执行下去了。

 2.第一种方式,因为没有sleep或者wait操作,线程并没有进入到阻塞状态的可能性,那么这时候,我们怎么样判断线程已经被打断了呢,JDK已经给我们提供了一个方法isInterrupted(),所以我们必须把while(ture),替换成while(!isInterrupted()),但是这里需要注意的是,当存在sleep或者wait操作时,即使我们把while(ture),替换成while(!isInterrupted())也是不能结束掉该线程的。

 当然,无论我们采用上面的那种方式都无法消除延迟这是线程处理中永远无法避免的问题,我们只有在实际的使用中尽量的避免我们的业务逻辑会受到这个问题所带来的影响。

4.线程的阻塞状态

  当处于就绪状态的线程得了cup时间片就开始运行,这时线程处于运行状态,当CPU时间片用完后,该线程有进入到了就绪状态,但是,还有以下几种情况可能是线程进入到阻塞状态:

  1.线程调用了sleep方法,主动的放弃了CPU的相关资源;

  2.线程在进行某种IO操作,在操作过程中线程被阻塞掉了;

  3.线程在执行的过程中,需要某一资源,而该资源正被另外的线程占用,这时候该线程必须等待,其他线程释放该资源;

  4.线程调用了wait方法,在等待notify方法的通知;

  那么和上面4种情况,对应的4种让线程恢复到就绪状态的方式如下(注意结束阻塞状态的线程,线程进入的是就绪状态,而不是马上进入运行状态,它必须等待下一次,CPU时间片的到达。

  1.调用sleep休眠的时间到了;

  2.IO操作完成;

  3.得到另一线程占用的资源;

  4.另一对象通过notify()或notifyAll()方法通知唤醒;

4.线程的死亡状态

  当线程的run方法运行完毕,线程就进入了死亡状态。当然还有一些意外的情况了,如线程在执行过程中出现了异常或者错误,而我们的程序有没有捕获该异常或错误,那这时该线程也就结束运行了;当然还有一个方法stop,不过,这个方法我们前面已经提到过,java已经废弃了这个方法,因为,这个方法可能会引起死锁。

  可以通过isAlive方法来判断线程是否还活着,在线程处于就绪,运行,阻塞状态时,调用该方法的返回值都是ture,在调用start方法前和run方法执行完成之后,调用该方法返回值为false,当然,一个处于死亡状态的线程,不能再调用start方法,start方法只能调用一次,且调用时线程必须处于新建状态。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java是一种广泛使用的编程语言,有简单、面向对象、跨平台等特点。下面是Java学习的一些重要知识点和学习笔记: 1. Java基础: - 数据类型:Java提供了多种数据类型,包括基本数据类型和引用数据类型。 - 控制流程:学习如何使用条件语句(if-else、switch)、循环语句(for、while)等控制程序的流程。 - 数组:了解如何声明、初始化和操作数组。 - 方法:学习如何定义和调用方法,以及方法的参数和返回值。 - 类和对象:理解类和对象的概念,学习如何定义类、创建对象和使用类的成员变量和方法。 - 继承和多态:掌握继承和多态的概念,了解如何使用继承创建子类,并实现方法的重写和多态的应用。 2. 面向对象编程: - 封装:学习如何使用访问修饰符(public、private、protected)来控制类的成员的访问权限。 - 继承:了解继承的概念和作用,学习如何使用extends关键字创建子类。 - 多态:理解多态的概念和实现方式,学习如何使用父类引用指向子类对象,实现方法的动态绑定。 3. 异常处理: - 异常的分类:了解异常的分类(Checked Exception和Unchecked Exception)和常见的异常类型。 - 异常处理机制:学习如何使用try-catch语句捕获和处理异常,以及使用throws关键字声明方法可能抛出的异常。 4. 输入输出: - 文件操作:学习如何读写文件,包括使用File类、字节流和字符流等。 - 序列化:了解对象的序列化和反序列化,学习如何将对象保存到文件或网络中。 5. 集合框架: - 学习Java提供的集合框架,包括List、Set、Map等常用的集合类,以及它们的特点和用法。 6. 多线程编程: - 学习如何创建和管理线程,了解线程同步和线程间通信的方法。 7. 数据库连接: - 学习如何使用Java连接数据库,执行SQL语句,进行数据的增删改查操作。 以上是Java学习的一些重要知识点和学习笔记,希望对你有帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值