JAVA_线程


一、线程的基本概念

       在操作系统中两个比较容易混淆的概念是进程(process)和线程(thread)。操作系统中的进程是资源的组织单位。进程有一个包含了程序内容和数据的地址空间,以及其它的资源,包括打开的文件、子进程和信号处理器等。不同进程的地址空间是互相隔离的。而线程表示的是程序的执行流程,是CPU调度的基本单位。线程有自己的程序计数器、寄存器、栈和帧等。引入线程的动机在于操作系统中阻塞式I/O的存在。当一个线程所执行的I/O被阻塞的时候,同一进程中的其它线程可以使用CPU来进行计算。这样的话,就提高了应用的执行效率。线程的概念在主流的操作系统和编程语言中都得到了支持。
       一部分的Java程序是单线程的。程序的机器指令按照程序中给定的顺序依次执行。Java语言提供了java.lang.Thread类来为线程提供抽象。有两种方式创建一个新的线程:一种是继承java.lang.Thread类并覆写其中的run()方法,另外一种则是在创建java.lang.Thread类的对象的时候,在构造函数中提供一个实现了java.lang.Runnable接口的类的对象。在得到了java.lang.Thread类的对象之后,通过调用其start()方法就可以启动这个线程的执行。
       一个线程被创建成功并启动之后,可以处在不同的状态中。这个线程可能正在占用CPU时间运行;也可能处在就绪状态,等待被调度执行;还可能阻塞在某个资源或是事件上。多个就绪状态的线程会竞争CPU时间以获得被执行的机会,而CPU则采用某种算法来调度线程的执行。不同线程的运行顺序是不确定的,多线程程序中的逻辑不能依赖于CPU的调度算法。
  Windows操作系统是支持多线程的,它可以同时执行很多个线程,也支持多进程,因此Windows操作系统是支持多线程多进程的操作系统。Linux和Uinux也是支持多线程和多进程的操作系统。DOS就不是支持多线程和多进程了,它只支持单进程,在同一个时间点只能有一个进程在执行,这就叫单线程。
  CPU难道真的很神通广大,能够同时执行那么多程序吗?不是的,CPU的执行是这样的:CPU的速度很快,一秒钟可以算好几亿次,因此CPU把自己的时间分成一个个小时间片,我这个时间片执行你一会,下一个时间片执行他一会,再下一个时间片又执行其他人一会,虽然有几十个线程,但一样可以在很短的时间内把他们通通都执行一遍,但对我们人来说,CPU的执行速度太快了,因此看起来就像是在同时执行一样,但实际上在一个时间点上。
  那什么才是真正的多线程?如果你的机器是双CPU,或者是双核,这确确实实是多线程。

二、线程的创建和启动

  在JAVA里面,JAVA的线程是通过java.lang.Thread类来实现的,每一个Thread对象代表一个新的线程。创建一个新线程出来有两种方法:第一个是从Thread类继承,另一个是实现接口runnable。VM启动时会有一个由主方法(public static void main())所定义的线程,这个线程叫主线程。可以通过创建Thread的实例来创建新的线程。你只要new一个Thread对象,一个新的线程也就出现了。每个线程都是通过某个特定的Thread对象所对应的方法run()来完成其操作的,方法run()称为线程体。

Demo1:实现Runnable接口创建和启动新线程
package com.liangdianshui;

public class ThreadRunable {
	public static void main(String args[]) {
		MyRunable mRunable = new MyRunable();
		// r1.run();//这个称为方法调用,方法调用的执行是等run()方法执行完之后才会继续执行main()方法
		new Thread(mRunable).start();  //启动一个线程
		for (int i = 0; i < 10; i++) {
			System.out.println("main:" + i);
		}
	}
}

/**
 * 自定义一个类,实现Runable接口 打印1-10
 *
 */
class MyRunable implements Runnable {
	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println("MyRunable:" + i);
		}
	}
}
运行结果:

       在我的机子上运行的结果是这样,在你们的机子上运行的结果也可能不一样的!他的运行原理是这样的:


Demo2:继承Thread类,重run()方法创建和启动新的线程
package com.liangdianshui;

public class ThreadExtendThread {
	public static void main(String[] args) {
		MyThread mThread = new MyThread();
		mThread.start(); // 开启一个新的线程
		for (int i = 0; i < 10; i++) {
			System.out.println("main:" + i);
		}
	}
}

/**
 * 继承Thread
 *
 */
class MyThread extends Thread {
	@Override
	public void run() {
		super.run();
		for (int i = 0; i < 10; i++) {
			System.out.println("MyThread: " + i);
		}
	}
}

  使用实现Runnable接口和继承Thread类这两种开辟新线程的方法,在选择上:应该优先选择实现Runnable接口这种方式去开辟一个新的线程。因为接口的实现可以实现多个,而类的继承只能是单继承。因此在开辟新线程时能够使用Runnable接口就尽量不要使用从Thread类继承的方式来开辟新的线程。

       通过上面的例子,我们可以这样理解线程,主线程就是一个部门的主管,当遇到比较耗时的工作的时候,他可以安排部门的其他员工帮忙做,然后他自己继续做下面的事情,最后只要知道员工完成的结果就行了~!

三、线程状态转换
3.1.线程控制的基本方法
3.2. sleep/join/yield方法介绍

Demo

package com.liangdianshui;

import java.util.Date;

public class ThreadRunable {
	public static void main(String args[]) {
		MyRunable mRunable = new MyRunable();
		// r1.run();//这个称为方法调用,方法调用的执行是等run()方法执行完之后才会继续执行main()方法
		new Thread(mRunable).start(); // 启动一个线程
		for (int i = 0; i < 10; i++) {
			System.out.println("main:" + i);
			if (i == 5) {
				try {
					System.out.println(new Date().toLocaleString());  //打印当前时间
					Thread.sleep(5000); // 让主线程休眠5秒
					System.out.println(new Date().toLocaleString());  //打印当前时间
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

/**
 * 自定义一个类,实现Runable接口 打印1-10
 *
 */
class MyRunable implements Runnable {
	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println("MyRunable:" + i);
		}
	}
}

运行结果:



Demo:

package com.liangdianshui;

import java.util.Date;

public class ThreadRunable {
	public static void main(String args[]) {
		MyRunable mRunable = new MyRunable();
		// r1.run();//这个称为方法调用,方法调用的执行是等run()方法执行完之后才会继续执行main()方法
		Thread mThread = new Thread(mRunable);
		mThread.start(); // 启动一个线程
		for (int i = 0; i < 10; i++) {
			System.out.println("main:" + i);
		}
		try {
			mThread.join();  //把子线程合并到主线程,等于是调用子线程的方法
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

/**
 * 自定义一个类,实现Runable接口 打印1-10
 *
 */
class MyRunable implements Runnable {
	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println("MyRunable:" + i);
			if (i == 2) {
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}
}
运行结果:

         


          join方法你可以理解为是直接停止了那个子线程,然后在主线程中继续运行!

Demo:
package com.liangdianshui;

import java.util.Date;

public class ThreadRunable {
	public static void main(String args[]) {
		MyThread1 t1 = new MyThread1("t1");
		MyThread1 t2 = new MyThread1("t2");
		t1.start();
		t2.start();
	}
}

class MyThread1 extends Thread {

	private String strName;

	public MyThread1(String str) {
		strName = str;
	}

	public void run() {
		for (int i = 0; i < 10; i++) {
			System.out.println(strName + ":" + i);
			try {
				Thread.sleep(1000); //为了更好的显示效果,增加延迟
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			if (i % 2 == 0) {
				yield();
			}
		}
	}

}
四、线程的优先级别

五、线程同步


六、总结
        这篇博文首先简单的介绍了什么是进程和线程,知道单个CPU不是真正意义上的多进程,CPU把自己的时间分成一个个小时间片,我这个时间片执行你一会,下一个时间片执行他一会,加上CPU的运行速度很快,因此像同时运行多个程序一样,然后了解实现Thread的两种方法,一种是实现Runable接口,一种是继承Thread类,最后讲了线程的一些方法!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值