在jvm运行时内存数据区中主要产生的java虚拟机内存占用资源大多都是为了提供java线程正常运行做准备的,在java中实现一个具备线程条件的方法有三个,分别是集成Thread类,实现Runable接口,实现callable接口。
进程实体的组成:
进程PCB控制块(记录进程状态与基本状况,调度优先级等控制信息)+程序代码+相关数据段
进程的任务:
资源分配和调度。
进程的性质:
-
动态性:进程是程序的一次执行,它有着创建、活动、暂停、终止等过程,具有一定的生命周期,是动态地产生、变化和消亡的。动态性是进程最基本的特征。
-
并发性:指多个进程实体,同存于内存中,能在一段时间内同时运行,并发性是进程的重要特征,同时也是操作系统的重要特征。引入进程的目的就是为了使程序能与其他进程的程序并发执行,以提高资源利用率。
-
独立性:指进程实体是一个能独立运行、独立获得资源和独立接受调度的基本单位。凡未建立PCB的程序都不能作为一个独立的单位参与运行。
-
异步性:由于进程的相互制约,使进程具有执行的间断性,即进程按各自独立的、 不可预知的速度向前推进。异步性会导致执行结果的不可再现性,为此,在操作系统中必须配置相应的进程同步机制。
-
结构性:每个进程都配置一个PCB对其进行描述。从结构上看,进程实体是由程序段、数据段和进程控制段三部分组成的。
线程的组成:
由线程ID、程序计数器、寄存器集合和堆栈(jvm运行时数据区的资源组成一个个java线程)组成。线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其他线程共享进程所拥有的全部资源
线程的任务:
引入线程后,进程的任务发生了改变,进程只作为除处理机以外系统资源的分配单元,线程则作为处理机的分配单元。
二者的关系:
进程可以由多个线程组成,如果说一个进程是一个正在参与工作的java实例,那么这个实例运行的方法就是一个个java线程,因为衣蛾Java实例所拥有的的方法可能不止一个,而且还会存在方法互调以及方法并行的情况。
继承Thread类创建线程:
package threads; //多线程并发测试1,测试run方法与sleep方法 class mythread extends Thread{ private String name; public mythread(String name){ this.name = name; } public void run(){ for(int i = 0; i < 5; i ++){ System.out.println(name +"运行 :"+i); try{ //sleep((int)(1000*Math.random()));产生随机数,随机线程运行的时间,随机时间决定运行次数。 sleep(100); //固定0.1s运行一个线程,当第一个线程运行0.1s后将其挂起运行第二个线程依次循环直至循环结束。 }catch(InterruptedException e){ e.printStackTrace(); } } } } public class test3 { public static void main(String[] args){ mythread t = new mythread("A"); mythread t1 = new mythread("B"); t.start(); t1.start(); } }
运行结果:
start()方法的调用后并不是立即执行多线程代码,而是使得该线程变为可运行态(Runnable),什么时候运行是由操作系统决定的。所有的多线程代码执行顺序都是不确定的,每次执行的结果都是随机的。 但是start方法重复调用的话,会出现java.lang.IllegalThreadStateException异常。
实现Runable接口创建线程
package threads; //java多线程之间的数据共享测试 class Thread2 implements Runnable{ private int tickets = 10; public void run(){ while (tickets >0) { //Thread.currentThread().getName()获取当前默认的进程名 System.out.println(Thread.currentThread().getName() + "出售机票,第" + tickets-- + "号"); } } } public class test5 { public static void main(String[] args){ Thread2 t = new Thread2(); Thread t1 = new Thread(t,"第1售票口"); Thread t2 = new Thread(t,"第2售票口"); Thread t3 = new Thread(t,"第3售票口"); t1.start(); t2.start(); t3.start(); for(int i=0;i<100;i++){ System.out.println("售票紧张!"); } } }
运行结果:
实现Runnable接口比继承Thread类所具有的优势:
1):适合多个相同的程序代码的线程去处理同一个资源
2):可以避免java中的单继承的限制
3):增加程序的健壮性,代码可以被多个线程共享,代码和数据独立
4):线程池只能放入实现Runable或callable类线程,不能直接放入继承Thread的类
龟兔赛跑:
class thread implements Runnable{ @Override public void run() { for(int i=1;i<=100;i++){ Boolean flag = BS(i); if(flag){ /*如果已经跑了100步直接跳出*/ break; } //让兔子睡0.001秒,其实这个线程跑的很快,睡0.001秒乌龟就有可能跑完全程。 if(Thread.currentThread().getName().equals("兔子")){ try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(Thread.currentThread().getName()+"跑了"+i+"步"); } } /*判断谁先跑了100步*/ public Boolean BS(int step){ if(step==100) { System.out.println(Thread.currentThread().getName()+"跑完了!"); return true; } return false; } } public class winner { public static void main(String[] args) { thread t = new thread(); new Thread(t, "兔子").start(); new Thread(t, "乌龟").start(); } }
运行结果: