在讲解多线程前,我们必须理解什么是多线程?而且很多人都会将进程和线程做对比。
进程和线程
进程:进程是操作系统结构的基础,是一次程序的执行,是一个程序及其数据在处理机上顺序执行时所发生的活动,是程序在一个数据集合上运行的过程,它是系统进行资源分配和调度的一个独立单位。或者这样理解,进程是一块包含了某些资源的内存区域。操作系统利用进程把它的工作划分为一些功能单元。
那么进程和程序有什么关系呢?简单的说,一个程序至少有一个进程。
线程:是进程中某个单一顺序的控制流。也被称为轻量进程。程序执行流的最小单位。在一个程序中,这些独立运行的程序片段就叫做”线程”(Thread)。或者这样理解,线程是进程中所包含的一个或多个执行单元。进程还拥有一个私有的虚拟地址空间,该空间仅能被它所包含的线程访问。
进程和线程的关系:
(1)一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。线程是操作系统可识别的最小执行和调度单位。
(2)资源分配给进程,同一进程的所有线程共享该进程的所有资源。同一进程中的多个线程共享代码段(代码和常量),数据段(全局变量和静态变量),扩展段(堆存储)。但是每个线程拥有自己的栈段,栈段又叫运行时段,用来存放所有局部变量和临时变量。
(3)处理机分给线程,即真正在处理机上运行的是线程。
(4)线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。
多线程:就是同时有多个线程执行,共同维护程序中的数据。(个人理解)
多线程实现
那么,在Java中如何实现多线程呢??
解析:在Java中,实现多线程有两种方式。
方式一:用户自定义一个类,继承自Thread类,重写该类的run方法
方式二:用户自定义一个类,实现Runnable接口,并且重写接口的run方法
方式一用法:
案例:我们在main方法中写一个for循环,循环1000次。并且开启一个子线程。也循环1000次。
代码如下:
1 public class MyThread { 2 3 public static void main(String[] args) throws InterruptedException { 4 5 //设置并开启多线程 6 7 MyThreadTest thread=new MyThreadTest(); 8 9 thread.start(); 10 11 for (int i = 1; i <=1000; i++) { 12 13 System.out.println("我是心如止水的主线程的第"+i+"次输出"); 14 15 } 16 17 } 18 19 } 20 21 //俺们自己写的类:继承自Thread类 22 23 class MyThreadTest extends Thread{ 24 25 public void run(){ 26 27 for (int i = 1; i <=1000; i++) { 28 29 System.out.println("我是害羞的子线程A的"+i+"次输出"); 30 31 } 32 33 } 34 35 } 36 37
方式二用法:
1 public class MyThread { 2 3 public static void main(String[] args) throws InterruptedException { 4 5 //设置并开启多线程 6 7 MyThreadTestiI mi=new MyThreadTestiI(); 8 9 Thread thread=new Thread(mi); 10 11 thread.start(); 12 13 for (int i = 1; i <=1000; i++) { 14 15 System.out.println("我是心如止水的主线程的第"+i+"次输出"); 16 17 } 18 19 } 20 21 } 22 23 24 25 //俺们自己写的类:实现了Runnable接口 26 27 class MyThreadTestiI implements Runnable{ 28 29 public void run(){ 30 31 for (int i = 1; i <=1000; i++) { 32 33 System.out.println("我是害羞的子线程A的"+i+"次输出"); 34 35 } 36 37 } 38 39 } 40 41
线程休眠
在程序的执行过程中,如何让程序中某个线程暂停一段时间呢?
案例:写一个小程序,在子线程中,每循环一次,就让该线程休眠1s。
Main方法中代码如下:
1 //线程休眠 2 3 System.out.println("程序开始"); 4 5 new Thread(){ 6 7 public void run(){ 8 9 for (int i = 1; i <=10; i++) { 10 11 //每循环一次,让程序休眠1s 12 13 try { 14 15 //这里, 必须用try,catch包裹,否则编译无法通过 16 17 //当然这里也不支持在方法上声明 throws Exception 18 19 //因为当前执行的run方法是子类的,根据异常的知识我们知道 20 21 //子类的方法的异常声明必须是父类方法异常声明的子集。但是 22 23 //我们通过查看代码可知run方法是没有进行异常声明的,所以 24 25 //这里只能采取try catch的方式。 26 27 //02。另外这里直接用的sleep,而不是 Thread. 28 29 //currentThread().sleep(millis),原因是 30 31 //sleep()方法属的类是Thread类的子类,由于Thread 32 33 //类中有sleep方法,所以在子类中可以直接使用sleep方法。 34 35 sleep(1000); 36 37 } catch (InterruptedException e) { 38 39 e.printStackTrace(); 40 41 } 42 43 System.out.println("第"+i+"次循环"); 44 45 } 46 47 } 48 49 }.start(); 50 51 52 53
守护线程:
1 //第一个线程 2 3 Thread t1=new Thread(){ 4 5 public void run(){ 6 7 for (int i = 1; i <=3; i++) { 8 9 System.out.println("我是第一个线程第"+i+"次循环"); 10 11 try { 12 13 Thread.sleep(1000); 14 15 } catch (InterruptedException e) { 16 17 e.printStackTrace(); 18 19 } 20 21 } 22 23 } 24 25 }; 26 27 //第二个线程 28 29 Thread t2= new Thread(){ 30 31 public void run(){ 32 33 for (int i = 1; i <=23; i++) { 34 35 System.out.println("我是第 2 个线程第"+i+"次循环"); 36 37 try { 38 39 Thread.sleep(1000); 40 41 } catch (InterruptedException e) { 42 43 e.printStackTrace(); 44 45 } 46 47 } 48 49 } 50 51 }; 52 53 //设置线程2为守护线程:当虚拟机发现所有的线程都为守护线程的时候,虚拟机体退出 54 55 t2.setDaemon(true); 56 57 t1.start(); 58 59 t2.start();
好了,咱们今天的探讨到此结束!