/**
* @author StormWangxhu
* @version 创建时间:2017年11月8日 上午9:41:19
*
*/
今天来学习线程。先来了解几个概念。
1、进程
1、定义:
每一个独立运行的程序都可以称为进程,即正在运行的程序。
目前大部分计算机上安装的都是多任务操作系统,既可以同时执行多个应用程序,最常见Windows,Linux,UNIX等。
2、多进程实质:
在计算机中,所有的应用程序都是由CPU执行的。对于一个CPU而言,在某一个时间点只能执行一个程序,也就是只能执行一个进程。操作系统会为一个进程分配一段有限的CPU使用时间,CPU在这段时间中执行某一个进程,然后会在下一段时间执行另一个进程。CPU运行速度很快,可在极短时间内在不同进程之间切换,给人以错觉。
2、线程
1、定义:
一个进程中可执行多个单元,这些单元称为线程。操作系统中每一个进程中至少存在一个线程。
2、
(1)单线程程序——–代码按照调用顺序依次往下执行,不出现交替执行。
(2) 多线程程序——-多段程序代码交替执行。即一个进程在执行过程中可以产生多个单线程,这些单线程运行时相互独立,并发执行。
实质:
依旧是右CPU来调度。
2、1、线程的创建
两种方式:
(1)、继承Java.lang包下的Thread类,覆写其run()方法,在run()方法中实现运行在线程上的代码。
(2)、实现java.lang包下的Runnable接口,同样在run()方法中实现运行在线程上代码。
先来看第一种方法:
package com.stormwang.ThreadDemo;
/**
* @author StormWangxhu
* @version 创建时间:2017年11月8日 上午9:41:19
*
*/
public class CreateThreadDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
MyThread myThread = new MyThread();
myThread.run();
while(true) {
System.out.println("main方法正在执行。");
}
}
}
class MyThread {
public void run() {
// TODO Auto-generated method stub
while (true) {
System.out.println("MyThread的run()方法正在main()中执行。");
}
}
}
运行:
会看到一直在运行一条语句。实则是单线程导致。
修改一下,继承Thread类。
package com.stormwang.ThreadDemo;
/**
* @author StormWangxhu
* @version 创建时间:2017年11月8日 上午9:41:19
*
*/
public class CreateThreadDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
MyThread myThread = new MyThread();
myThread.start();
for(int i=0;i<50;i++) {
System.out.println("main方法正在运行。"+i);
if (i==20) {
break;
}
}
}
}
class MyThread extends Thread{
public void run() {
for(int j=0;j<50;j++) {
System.out.println("MyThread的run()方法正在main()中执行。"+j);
if (j==20) {
break;
}
}
}
}
运行:
回看到,在交替运行。
再来看第二种方法:
继承Thread类有一定的局限性。因为Java支持单继承,一个类一旦继承了某个父类就无法再继承Thread类。例如学生类Student类继承了Person类,就无法再继承Thread类。
所以,Thread提供了另一个构造对象;
Thread(Runnable target);
实现Runnable接口中run()方法。
package com.stormwang.ThreadDemo;
/**
* @author StormWangxhu
* @version 创建时间:2017年11月8日 上午10:31:51
*
*/
public class RunnableDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
RunnableTest ruTest = new RunnableTest();
Thread thread = new Thread(ruTest);
thread.start();
int count = 0 ;
while (true) {
System.out.println("main方法正在运行。"+count);
count++;
if (count==20) {
break;
}
}
}
}
class RunnableTest implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
for(int i=0;i<50;i++) {
System.out.println("Runnable中的run()方法正在运行。"+i);
if (i==20) {
break;
}
}
}
}
运行:
也实现了多线程。
两种实现方式的区别和对比分析
以一个窗口买票的例子演示两种方式的区别:
假设有四个窗口,买100张票。
以第一中方式:
package com.stormwang.ThreadDemo;
/**
* @author StormWangxhu
* @version 创建时间:2017年11月8日 上午11:06:38
*
*/
public class TicketWindowDemo {
public static void main(String[] args) {
//创建4个线程
new TicketWindowTest().start();
new TicketWindowTest().start();
new TicketWindowTest().start();
new TicketWindowTest().start();
}
}
class TicketWindowTest extends Thread{
private int ticketNum = 100;
public void run() {
while (true) {
if (ticketNum>0) {
Thread thread = Thread.currentThread();//获取当前线程
String th_name = thread.getName();
System.out.println(th_name+" 正在发售第 "+ticketNum+" 张!");
ticketNum--;
}
}
}
}
运行:
会看到,每一个售票窗口各自买了100张票,显然与实不符合。
再看第二种方式:
package com.stormwang.ThreadDemo;
/**
* @author StormWangxhu
* @version 创建时间:2017年11月8日 上午11:19:46
*
*/
public class TicketsWindowDemo_2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
TicketWindow_1 ticketWindow_1 = new TicketWindow_1();
Thread thread = new Thread(ticketWindow_1, "窗口1");
Thread thread2 = new Thread(ticketWindow_1, "窗口2");
Thread thread3 = new Thread(ticketWindow_1, "窗口3");
Thread thread4 = new Thread(ticketWindow_1, "窗口4");
thread.start();
thread2.start();
thread3.start();
thread4.start();
}
}
class TicketWindow_1 implements Runnable{
private int ticketNumbet = 100 ;
@Override
public void run() {
while(true) {
if (ticketNumbet>0) {
Thread thread = Thread.currentThread(); //获取当前运行run()方法的线程
String name = thread.getName();//得到线程的名称。
System.out.println(name+" 正在发售 第 "+ticketNumbet-- +" 张!");
}
}
}
}
运行:
可以看到,四个线程共享一个runnable资源。实现了共买100张票。
以上比较,实现Runnable接口有以下几点好处:
1、适合多个相同程序代码的线程去处理同一个资源的情况,把线程与程序代码、数据有效的分离,很好的体现了面向对象的设计思想。
2、可以避免由于Java的单继承
带来的局限性。在开发中经常碰到这样情况,就是使用一个继承了某一个父类的子类创建线程,由于一个类不能同时有两个父类,所依不能用继承Thrad类的方式,那么就只能采用Runnable接口的方式。