1、程序、进程与线程
程序是计算机指令的集合,它以文件的形式存储在磁盘上。
进程:是一个程序在其自身的地址空间中的一次执行活动
进程是资源申请、调度和独立运行的单位,因此,它使用系统中的运行资源;而程序不能申请系统资源,不能被系统调度,也不能作为独立运行的单位,因此,它不占用系统的运行资源
线程:是进程中的一个单一的连续控制流程。一个进程可以拥有多个线程。
线程又称为轻量级进程,它和进程一样拥有独立的执行控制,由操作系统负责调度,区别在于线程没有独立的存储空间,而是和所属进程中的其它线程共享一个存储空间,这使得线程间的通信远较进程简单。
Java运行环境——单进程多线程
多线程的目的是为了最大限度的利用CPU资源。
Java编写程序都运行在在JVM中,在JVM的内部,程序的多任务是通过线程来实现的。启动一个java应用程序,就会启动一个JVM进程。在同一个JVM进程中,有且只有一个进程,就是它自己。在这个JVM环境中,所有程序代码的运行都是以线程来运行。
Java线程实现的两种方式
Java在语言级提供了对多线程程序设计的支持。
实现多线程程序的两种方式:
(1)从Thread类继承;
(2)实现Runnable接口。
继承Thread类
Thread类定义在java.lang包中,一个类只要继承了Thread类,此类就称为多线程操作类。在Thread子类中,必须明确的覆写Thread类中的run()方法,此方法为线程的主体
class 类名 extends Thread{
//属性;
//方法;
//覆写Thread类中的run()方法,此方法是线程的文体
Public void run(){
//线程文体。
}
}
class MyThread extends Thread{
private String name;
public MyThread(String name){
this.name = name;
}
public void run(){
for(int i=0; i<10; i++){
System.out.println(name +”运行:”+i);
}
}
}
public class ThreadDemo1{
public static void main(String args[]){
MyThread mt1=new MyThread(“线程A”);
MyTHread mt2=new Mythread(“线程B”);
mt1.start();
mt2.start();
}
}
线程类的使用误区:
直接调用线程run方法,并不会让一个线程启动,其效果实际上与一般的方法调用一样,只是在主线程中执行。
让一个线程启动的正确方法是使用Thread类定义中的start()方法。
public class ThreadDemo1{
public static void main(String args[]){
MyThread mt1=new MyThread(“线程A”);
MyTHread mt2=new Mythread(“线程B”);
mt1.start();
mt2.start();
}
}
线程调度
调度的方式分为:分时调度,抢占式调度
java虚拟机是抢占式调度,在java编程中,抢占式调度是指根据优先级来获得CPU的分配使用,如果同级则是根据随机选择。
Runnable
通过实现Runnable接口的方式来实现多线程,Runnable接口中只定义了一个抽象方法:
public void run();
通过Runnable接口实现多线程:
class 类名 implements Runnable{
//属性;
//方法;
//覆写Runnable接口的run()方法
public void run(){ ……} //线程主体
}
Class MyThread implements Runnable{
private String name;
public MyThread(String name){
this.name = name;
}
public void run(){
for(int i=0;i<10;i++){
System.out.println(name+”运行:”+i);
}
}
}
public class RunnableDemo{
MyThread mt1= new MyThread(“线程A”);
MyThread mt2 = new MyThread(“线程B”);
Thread t1 = new Thread(mt1);
Thread t2 = new Thread(mt2);
t1.start();
t2.start();
}
Thread类与Runnable接口的联系
Thread类的定义
public class Thread extends Object implements Runnable{
public Thread(Runnable){
init(null, target, name, 0);
}
private void init(…, Runnable target,…){
……
this.target = target;
}
public void run(){
target.run();
}
}
使用Thread类在操作多线程的时时候无法达到资源共享的目的,而使用Runnable接口实现的多线程操作可以实现资源共享。
Thread类与Runnable接口的区别
Runnable较Thread类的优点:
适合多个相同程序代码的线程去处理同一个资源;
可以避免由于单继承局限所带来的影响
增强了程序的健壮性,代码能够被多个线程共享
线程的状态
多线程在操作中也是有一个固定的操作状态:
创建状态:准备好了一个多线程对象:Thread = new Thread();
就绪状态:调用了start()方法,等待CPU进行调度
运行状态:执行run()方法
阻塞状态:暂时停止执行,可能将资源交给其他线程使用
终止状态(死亡状态):线程执行完毕,不再使用
线程的同步与死锁
什么时候需要线程同步?
火车票出售,将不同的售票点当成不同的线程,那这些线程都共享同一份数据——火车票。A售票点工作人员查询系统,目前还有1张票,准备出售时,有急事离开一会,此时,B售票点工作人员查询系统,还有1张票,出票,A工作人员回来后,再出售车票,此时票数不对了。
资源共享的问题
Class MyThread implements Runnable{
private int ticket = 5;
public void run(){
for(int i=0; i<100; i++){
if(ticket>0){
try{
Thread.sleep(300);
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(“票数:”+ticket--);
}
}
}
}
Public class TestDemo{
MyThread mt = new MyThread();
Thread t1 = new Thread(mt);
Thread t2 = new Thread(mt);
Thread t3 = new Thread(mt);
t1.start();
t2.start();
t3.start();
}
如何进行线程同步
解决资源共享的同步操作问题,有两种方式:
1,同步代码块:
synchronized(同步对象){
// 需要同步的代码;
}
同步的时候必须指明同步的对象,一般情况下会将当前对象作为同步对象,用this变量引用。
2,同步方法:
除了可以将需要的代码进行同步之外,也可以将一个方法声明为同步方法。
同步方法定义格式:
syschronized 方法返回类型 方法名(参数列表){
//方法体
}
线程死锁
资源共享时需要进行同步操作。
程序中过多的同步可能产生死锁