几个基本概念:
程序:数据和代码集合,是应用程序执行的脚本
进程:程序的一次执行过程,是系统运行程序的基本单位。程序是静态的,进程是动态的。系统运行一个程序即一个进程从创建、运行到消亡的过程。
多任务:在一个系统中可以同时运行多个程序,即有多个独立运行的任务,每个任务对应一个进程。
线程:比进程更小的运行单元,是程序中耽搁顺序的流控制,一个进程可以包含多个线程。
备注:同个进程下的多个线程是共享该进程下的资源的。如果一个程序要执行(即变为进程)系统要为其开销资源(比较大的)。所以进程之间的通信消耗的资源比较大,进程之间的通信开销比较小。简单理解:QQ、Word、PPS它们就是一个个进程,而QQ里面同时可以和多个好友聊天就是多线程。
备注:可以那么理解,如果把一个班级比作一个进程的话,那么该班级下面所有的学生就是该进程下的线程了,改班级下的书桌、粉笔、等等资源是所有学生所共享的。
备注:每个java程序启动后,JVM虚拟机就会自动创建一个主线程。
实现多线程的两种常用方式:(继承Thread、Runnable接口)
备注:不管是哪种方式想要启动线程都要调用Thread.start()方法,不是run()方法。
备注:推荐使用接口的方式,实现Runnable接口可以避免多继承的问题
Thread类:它本身也是继承自Runnable接口的。
Runnable接口:该接口中指定义了一个方法,即run()方法。
备注:启动线程的方法是start(),千万不要以为是run()方法启动线程。
线程的四种状态:
新建线程态(new Thread)
就绪状态(可运行状态 Runnable)
运行状态(Running)
阻塞(Not Runnable)
死亡态(Dead)
多线程重点总结
1、Java中如果我们自己没有产生线程,那么系统就会给我产生一个线程(主线程,main方法就是在主线程上运行),我们的程序都是有线程来执行的。
2、进程:执行中的程序(程序是静态的概念、进程是动态的概念)。
3、线程的实现由两种方式,第一种方式是继承Thread类,然后重写方法;第二种是实现Runnable接口,然后实现其run方法。推荐使用第二种方式
4、将我们希望线程执行的代码放到run方法中,然后通过start方法来启动线程(只有Thread的start方法才能启动线程,没有其它的方法了。)。start 方法首先为线程的执行准备好系统资源,然后去调用run方法。当某个类继承了Thread之后,该类就叫做一个线程类
5、一个进程至少包含一个线程,线程共享所属进程的资源。
6、对于单核cpu来说,某一时刻只能有一个线程在执行(微观串行),从宏观角度来看,多个线程在同时执行(宏观并行)。多核cpu能真正意义上实现微观并行。
7、
1、Thread类也实现了Runnable接口,因此实现了Runnable接口中的方法
2、当生成一个线程对象时,如果没有为其指定名字,那么线程对象的名字将使用默认的Thread-number形式,number数值是自增的,并且所有的Thread对象共享它,因为它是static成员变量。
3、当使用第一种方式来生成线程对象时,我们需要重写run方法,因为Thread类的run方法什么事情都没有做
4、当我们使用第二种方式生成对象的时,我们需要实现Runnable接口的run方法,然后使用new Thread(Runnable target),target是已经实现了Runnable接口的对象。最后启动线程还是要用到Thread的start方法。但是最终还是会调用target已经重写了的run方法
8、关于成员变量和局部变量:如果一个变量是成员变量,那么多个线程对同一个对象的成员变量操作时,他们对该成员变量是彼此影响的。(也就是说一个线程对成员变量的改变会影响到另一个线程)。注意是对同一个对象操作,如果是不同对象就不存在所谓的影响了。
9、如果一个变量是局部变量,那么每个线程都会有一个该局部变量的拷贝,一个线程对该局部变量的改变不会影响到其他线程。
10、停止线程的方式,不能使用Thread类的stop方法来终止线程执行。一般要设定一个变量,在run方法中判断检查该变量,如果该变量无法满足一定条件,那么我们就是run方法跳出循环或break。
11、不能依靠线程的优先级来决定线程的执行顺序(优先级只是相对的,越高代表被cpu调度的机率越大)
12、synchronized关键字:当synchronized关键字修饰一个方法的时候,该方法叫做同步方法。
13、Java中的每一个对象都有一个锁(lock)或者叫做监视器(monitor),当访问某个对象的synchronized方法时,表示将该对象上锁,此时其它任何线程都无法再去访问该synchronized方法了,直到之前的那个线程执行方法完毕后(或者抛出了异常),将该对象的锁释放掉,其它线程才能可以去访问该synchronized方法。
14、如果一个对象有多个synchronized方法,某一时刻某个线程已经进入到某个synchronized方法,那么在该方法没有执行完毕前,其它线程是无法访问该对象的任何synchronized方法的。
15、如果某个synchronized方法是static的,那么当线程访问该方法时,它的锁并不是synchronized方法所在的对象,而是synchronized方法所在的对象所对应的class对象,因为java中无论一个类有多少个对象,这些对象都会对应唯一一个Class对象,因此当线程分别访问同一个类的两个对象的的两个static,synchronized方法时,他们呢的执行顺序也是顺序,也就是说一个线程先去执行方法,执行完毕后另一个线程才开始执行。
16、synchronized代码块,格式如下:
synchronized(object){
}
17、synchronized方法是一种粗粒度的并发控制,某一时刻,只能有一个线程执行该synchronized方法;synchronized块则是一种细粒度的并发控制,只会将块中的代码同步,位于方法内、synchronized块之外的代码是可以被多个线程同时访问的。
18、wait与notify方法都是定义在Object类中,而且是final的,因此会被所有的java类所继承并且无法重写。这两个方法要求在调用的时候线程应该已经获得了对象的锁,因此对这两个方法的调用需要放在synchronized方法或块当中。当线程执行了wait方法时,它会释放掉对象的锁。
19、另一个会导致线程暂停的方法是Thread类的sleep方法,它会导致线程睡眠指定的毫秒数,但是线程在睡眠的过程是不会释放掉对象的锁的。(wait 和 sleep 都会使线程暂停,区别在于wait释放了对象的所,sleep不释放对象的锁。)