JAVA多线程基础
一、基础理论
1、进程:
狭义定义:进程就是程序的执行过程。
我们打开任务管理器的时候,如图,我们看到许多进程。
复杂一点说:进程就是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。
2、线程:
线程,有的时候被称为轻量级进程(LWP),是程序执行流的最小单元。LWP是一种实现多任务的方法。
3、线程与进程的区别:
说了这么多官方的解释,其实简单来说将:一个应用程序就是一个进程,而线程是一个进程内部的多个运行单位。
4、多线程:
举一个最常见的例子:在用户界面中,利用线程,用户可按下一个按钮,然后程序会立即作出响应,而不是让用户等待程序完成了当前任务以后才开始响应。
因此:多线程就是,将进程内部分为多个线程,线程同时进行。
多线程是共享一块内存空间和一组系统资源(在同一进程内),在程序内部可以互相调用(通过对象方法)。
线程本身的数据通常只有寄存器数据,以及程序执行时使用的堆栈,线程切换负担小。
二、java中的多线程实现
多线程模型是将代码的调用放到一个独立的运行单元——即线程中,让多个调用并行执行。
多线程模型代码示意如下:
public void ma(){ //在线程中调用mb();---> //在线程中调用mc();---> //在线程中调用md();---> System.out.println("三个线程并行执行。。"); } public void mb(){ } public void mc(){ } public void md(){ }
那么java中如何实现多线程呢?
1、继承Thread类实现线程:
重写Thread类的run()方法,调用start()方法启动线程。
public class Test extends Thread { public static void main(String[] args) { for (int t = 1; t < 10000; t++) { Test tm = new Test(t);// 构造Thread对象 tm.start();// 启动线程 } } // 构造器传入这个线程的ID public Test(int id) { this.id = id; } // 线程运行入口 public void run() { // 循环输出当点时间点 while (true) { long currentTime = System.currentTimeMillis(); System.out.println(id + "号线程:" + currentTime); } } private int id; }
2、实现Runnable接口创建线程
因为java是单继承的,为了方便类既使用多线程又可以继承其它类,所以java中还提供了另一种方法。
public class RunnableTest implements Runnable { public static void main(String[] args) { for (int t = 1000; t < 1010; t++) { RunnableTest rt = new RunnableTest(t);// 创建Runnable对象 Thread thread = new Thread(rt);// 构造Thread对象 thread.start();// 启动线程 } } // 构造器传入这个线程的ID public RunnableTest(int id) { this.id = id; } // 线程运行入口 public void run() { // 循环输出当前时间点 while (true) { long currentTime = System.currentTimeMillis(); System.out.println(id + "号线程:" + currentTime); } } private int id; }
线程的暂停:
改进run()方法。
public void run() { while (true) { long currentTime = System.currentTimeMillis(); System.out.println(id + "号线程:" + currentTime); try { Thread.sleep(this.id * 1000); } catch (InterruptedException ie) { System.out.println("线程在sleep中收到中断信号,但不退出:" + ie); } } }
Thread.sleep(long time)方法只会让被调用的线程暂停(或者叫做挂起)——不是停止,也不是退出,这个时间一过,线程对象又会被VM调度到运行状态。
3、以内部类的方式创建线程
public class ThreadTest { public static void main(String[] args) { ThreadTest tt = new ThreadTest(); for (int i = 0; i < 10; i++) { tt.startMyThread(i); } } /** * 这个方法会启动一个匿名线程线程 */ public void startMyThread(int threadID) { // 要传入匿名线程内使用的参数必须定义为final型 final int id = threadID; Runnable runner = new Runnable() { public void run() { int i = 10; boolean flag = true; while (flag) { try { Thread.sleep(3000); // 在匿名线程类中调用类中的其它方法 otherMethod(id); if (i > 13) { flag = false; } } catch (Exception ef) { } } } }; Thread t = new Thread(runner); t.start(); } // 测试方法 private void otherMethod(int i) { System.out.println("可以直接调用类中的其它方法:" + i); } }
// 要传入匿名线程内使用的参数必须定义为final型
final int id = threadID;
这个方法非常方便:在一个方法调用中启动匿名内部线程,线程可以直接使用类中的属性和方法。
4、继承TimerTask类实现线程的定时执行
public class TimerPrint extends TimerTask { public static void main(String[] args) { Timer timer = new Timer();// 创建一个定时器对象 TimerPrint dw = new TimerPrint();// 创建一个定时任务对象 // 调度这个定时任务在程序启动5秒后,每隔3秒运行一次 timer.schedule(dw, 5000, 3000); } // 重写继承自TimerTask中的run方法,作为线程运行时被调用 public void run() { runcount++; System.out.println(runcount + "次定时运行:" + System.currentTimeMillis() / 1000); } private int runcount = 0; }
三、多线程的优缺点
优点:
1、使用线程可以把占据时间长的程序中的任务放到后台去处理
2、用户界面可以更加吸引人,这样比如用户点击了一个按钮去触发某些事件的处理,可以弹出一个进度条来显示处理的进度
3、程序的运行速度可能加快
4、在一些等待的任务实现上如用户输入、文件读写和网络收发数据等,线程就比较有用了。在这种情况下可以释放一些珍贵的资源如内存占用等等。
5、多线程技术在IOS软件开发中也有举足轻重的位置。
缺点:
1、如果有大量的线程,会影响性能,因为操作系统需要在它们之间切换。
2、更多的线程需要更多的内存空间。
3、线程可能会给程序带来更多“bug”,因此要小心使用。
4、线程的中止需要考虑其对程序运行的影响。
5、通常块模型数据是在多个线程间共享的,需要防止线程死锁情况的发生。