线程

线程

1、进程、线程的基本概念

进程:是指运行中的应用程序,每个进程都有自己独立的地址空间(内存空间)。比如用户点击ie浏览器,就启动了一个进程,操作系统就会为该进程分配独立的地址空间,当用户再次点击ie浏览器图标,就又启动了一个进程,操作系统将为新的进程分配新的独立的地址空间。

线程:是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其他线程共享进程所拥有的全部资源。一个线程可以创建和撤销另一个线程,同一进程中的多个线程可以并发执行,线程有就绪、阻塞和运行三种基本状态。

总结:1. 线程是轻量级的进程

​ 2. 线程没有独立的地址空间(内存空间)

​ 3. 线程是由继承创建的(寄生在进程)

​ 4. 一个进程可以拥有多个线程

2、线程的5种状态

线程从创建、运行到结束总是处于下面五个状态之一:

  • 新建状态:当用new操作符创建一个线程时, 例如new Thread®,线程还没有开始运行,此时线程处在新建状态。 当一个线程处于新生状态时,程序还没有开始运行线程中的代码

  • 就绪状态:一个新创建的线程并不自动开始运行,要执行线程,必须调用线程的start()方法。当线程对象调用start()方法即启动了线程,start()方法创建线程运行的系统资源,并调度线程运行run()方法。当start()方法返回后,线程就处于就绪状态。
    处于就绪状态的线程并不一定立即运行run()方法,线程还必须同其他线程竞争CPU时间,只有获得CPU时间才可以运行线程。因为在单CPU的计算机系统中,不可能同时运行多个线程,一个时刻仅有一个线程处于运行状态。因此此时可能有多个线程处于就绪状态。对多个处于就绪状态的线程是由Java运行时系统的线程调度程序(thread scheduler)来调度的。

  • 运行状态:当线程获得CPU时间后,它才进入运行状态,真正开始执行run()方法.

  • 阻塞状态:线程运行过程中,可能由于各种原因进入阻塞状态:
    1>线程通过调用sleep方法进入睡眠状态;
    2>线程调用一个在I/O上被阻塞的操作,即该操作在输入输出操作完成之前不会返回到它的调用者;
    3>线程试图得到一个锁,而该锁正被其他线程持有;
    4>线程在等待某个触发条件;
    ……

所谓阻塞状态是正在运行的线程没有运行结束,暂时让出CPU,这时其他处于就绪状态的线程就可以获得CPU时间,进入运行状态。

  • 死亡状态:有两个原因会导致线程死亡:

    1. run方法正常退出而自然死亡,
    2. 一个未捕获的异常终止了run方法而使线程猝死。
      为了确定线程在当前是否存活着(就是要么是可运行的,要么是被阻塞了),需要使用isAlive方法。如果是可运行或被阻塞,这个方法返回true; 如果线程仍旧是new状态且不是可运行的, 或者线程死亡了,则返回false.

    新建状态 new
    就绪状态 Runnable(可运行状态)
    运行状态 Running
    阻塞状态 Blocked
    死亡状态 Dead

3、线程的使用

​ 在java中一个类要当做线程来使用有两种方法。(开发线程的两种方式)

  1. 继承Thread类,并重写run函数。

  2. 实现Runnable接口,并重写run函数。

为什么要提供第二种方法呢?因为,比如你写的某个类已经继承了别的类,由于java中类只能单继承,所以这个类不就不能实现线程了吗。所以有了这种方法。

需求:请编写一个程序,该程序每隔一秒,在控制台输出: “hello world”。【拓展需求:当输出10次后,自动退出】

public class Demo1 {

	/**
	 * 1.	继承Thread类,并重写run函数
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		//创建一只猫
		Cat cat=new Cat();
		
		//启动线程,会导致run函数运行
		cat.start();
	}

}

//猫类
class Cat extends Thread{

	//重写run函数
	@Override
	public void run() {
		// TODO Auto-generated method stub
	
		int times=0;//统计次数
		while(true){
			
			try {
				//休眠1秒(1000毫秒=1秒)
				//sleep就让该线程进入阻塞状态(Blocked),并释放资源
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			times++;
			System.out.println("hello world"+times);
			
			//打印10次,跳出线程
			if(times==10){
				break;//退出while循环
			}
		}	
	}	
}

方法二:

public class Demo2 {

	/**
	 * 2、实现Runnable接口,并重写run函数
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		//实例化狗类
		Dog dog=new Dog();
		
		 //创建一个Thread对象
        Thread t = new Thread(dog);
        t.start();

	}
}

// 狗类
class Dog implements Runnable {

	@Override
	public void run() {
		// TODO Auto-generated method stub

		int times = 0;// 统计次数
		while (true) {

			try {
				// 休眠1秒(1000毫秒=1秒)
				// sleep就让该线程进入阻塞状态(Blocked),并释放资源
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			times++;
			System.out.println("hello world" + times);

			// 打印10次,跳出线程
			if (times == 10) {
				break;// 退出while循环
			}

		}
	}
}

4、多线程

需求:请编写一个程序,该程序可以接收一个整数n,创建一个线程,一个线程计算1+2+…+n,另一个线程每隔一秒在控制台输出,”我是线程,正在输出第xx个hello world”,xx要用具体的数字显示,这两个工作要求同时进行。

public class Demo3 {

	/**
	 * 多线程:
	 * 1、一个计算1+2+...+n
	 * 2、我是线程,正在输出第xx个hello world
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub

		//实例化Pig
		Pig pig=new Pig(10);
		
		//实例化Bird
		Bird bird=new Bird(10);
		
		//创建猪线程
		Thread t1=new Thread(pig);
		//创建鸟线程
		Thread t2=new Thread(bird);
		
		//启动两个线程
		t1.start();
		t2.start();
		
	}

}

//鸟说hello world
class Bird implements Runnable{
	
	int n=0;
	int times = 0;// 统计次数
	
	public Bird(int n){
		this.n=n;
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		
		while (true) {

			try {
				// 休眠1秒(1000毫秒=1秒)
				// sleep就让该线程进入阻塞状态(Blocked),并释放资源
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			times++;
	System.out.println("我是线程,正在输出第"+times+"个  hello world");

			// 打印n次,跳出线程
			if (times == n) {
				break;// 退出while循环
			}
		}
		
	}	
}

//猪算算术1+2+...+n
class Pig implements Runnable{
	
	int n=0;
	int result=0;//和
	
	int times = 0;// 统计次数
	
	public Pig(int n){
		this.n=n;
	}
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		
		while (true) {

			try {
				// 休眠1秒(1000毫秒=1秒)
				// sleep就让该线程进入阻塞状态(Blocked),并释放资源
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			result+=(++times);
			System.out.println("当前的结果:" + result);

			// 打印n次,跳出线程
			if (times == n) {
				break;// 退出while循环
			}
		}
	}	
}

​ 线程对象只能启动一个线程(不管是通过继承Thread,还是通过实现Runnable接口创建线程,它们的对象只能启动一次。否则就会抛出异常。

public class Demo4 {

	/**
	 * 功能:演示线程的注意事项
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		/*A a1=new A();
		
		Thread t1=new Thread(a1);
		t1.start();
		t1.start();
		*/
		
		B b1=new B();
		b1.start();
		b1.start();
		
	}
}

class A implements Runnable{

	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println("我是线程1.。。");
	}
	
}

class B extends Thread{

	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println("我是线程2.。。");
	}
}

多线程例子:(请编写一个程序,模拟一个机票售票系统:有三个售票点,在一天卖出2000张票。(注意是一共卖出2000张票,不是每个售票点都卖2000张))

public class Demo5 {

	/**
	 * 功能:模拟售票
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		//定义售票窗口
		TicketWindow tw1=new TicketWindow();
		
		//创建三个线程
		Thread t1=new Thread(tw1);
		Thread t2=new Thread(tw1);
		Thread t3=new Thread(tw1);
		
		//启动三个线程
		t1.start();
		t2.start();
		t3.start();

	}

}

//窗口售票类
class TicketWindow implements Runnable {
	
	//一共有2000张票
	private int nums=2000;

	@Override
	public void run() {
		// TODO Auto-generated method stub
		
		while(true){
            //代码要保证原子性(同步代码块)
            synchronized(this){
			
			//出票速度是一秒出一张
			try {
				Thread.sleep(1000);
			} catch (Exception e) {
				// TODO: handle exception
				e.printStackTrace();
			}
			
				//先判断是否还有票
				if(nums>0){
					
					//显示售票信息
			System.out.println("在售出第 "+nums+" 张票"+"--"
				+Thread.currentThread().getName());//得到当前线程名称
					
					nums--;
				}else{
					//售票结束
					break;
				}
			
			}
	}
}
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 1024 设计师:白松林 返回首页