java多线程基础知识
多线程:
什么是进程?什么是线程?
进程是程序的一次动态的执行过程,它经历了从代码加载、执行到执行完毕的一个完整的过程,这个过程也就是进程本身从产生,发展到最后消亡的过程。如果操作系统支持多进程的,我们称之为多进程的操作系统,例如Windows.多进程的操作系统能够“同时”运行多个进程(程序),由于CPU具备分时机制,所以每一个进程都能循环获得自己的CPU时间片。由于CPU执行速度非常的快,所示是的所有的程序好像是“同时”在运行。
线程是比进程更小的一个执行单位,我们可以把线程理解为程序中的某一个具体的功能。word文档中肯定有输入的功能,还有拼接检查的功能。或者说游戏中,操作的界面,还有背景音乐。所有支持多线程的进程,我们称之为多线程程序。Java就支持多线程开发。多线程是实现并发进制的一种有效的手段。所谓的多线程就是指一个进程中在执行过程中可以产生多个更小的程序单元,这些更小的程序单元称为线程。
线程时包含在进程中,如果一个进程被关闭了,那么这个进程中的线程也会被关闭,如果是一个线程关闭了,进程不一定会被关闭。
我们在传统的程序语言中,运行的顺序总是按照程序的流程运行,遇到if-else语句就会执行判断,遇到了for或者是while循环就会执行循环,重复的执行一些内容。最后程序还是按照一定的程序在运行,并且一次只能运行一个程序模块。
Java中的多线程打破了这种传统的束缚,所谓的线程(Thread)是指程序的运行流程,多线程机制则是指可以“同时”运行多个程序块。使程序变得更加的高效,也可以客服传统的程序语言所无法解决的问题。例如,有一些包含循环的线程可能要使用一段时间来进行运算,此时可以让另外一段线程来做其他的处理。
Java中如何实现多线程程序:
在Java中要想实现多线程的操作有两种手段:
1.继承Thread类
Thread类是java.lang包下的类,一个类只要继承了Thread类,此类就是多线程的实现类。在Thread的子类中,必须要对run方法进行重写,run方法是一个线程的执行方法。
线程类的定义格式:
访问权限修饰符 class 类名 extends Thread{
属性
方法
public void run(){
线程真正要执行的内容
}
}
注意:
1.虽然run方法是线程的执行方法,我们将线程需要执行的内容都写在了run方法的内部,但是run方法不是线程的启动方法。线程的启动方法是start().
2.一个线程不能重复的启动,否则会出现异常:java.lang.IllegalThreadStateException
2.实现Runnable接口
在java中也可以通过实现Runnable接口的方式实现多线程
通过Runnable接口的方式实现多线程的格式
访问权限修饰符 class 类名 implements Runnable{
属性
方法
public void run(){
}
}
注意:实现Runnable接口的方式,不能通过Runnable的接口的子类,直接实现线程的功能,我们还需要通过Thread来实现:Thread t = new Thread(Runnable的子类对象);
继承Thread类和实现Runnable接口的方式都可以实现多线程,二者有何区别:
继承Thread类的方式,由于使用了继承,受到单继承的影响。还不能共享数据。
实现Runnable接口的方式,显著的优势在于:
1.适合多个相同的程序代码的线程去处理同一个资源
2.可以避免由于Java的单继承带来的局限
3.增强了程序的健壮性,代码能够被多个线程共享,代码与数据是独立的。
综上所诉,以后我们在开发中尽量使用实现Runnable接口的方式。
线程的状态(生命周期):
要想实现多线程,必须在主线程中创建新的线程对象。任何线程一般具有五种状态,即新建、就绪、运行、阻塞、销毁。
线程常用的方法:
currentThread():获取当前正在执行的线程的对象。此方法是一个静态方法
getName():获取线程的名称
setName(String name):设置线程的名称
isAlive():判断线程是否正在运行
join():让一个线程强制执行。当某个线程被强制执行之后,这个线程如果没有执行完毕,其他的线程都会等待这个线程的执行,直到这个被强制执行的线程执行完毕为止。
sleep(long time):让线程休眠time秒,注意参数代表的是休眠的毫秒数
interrupt():中断线程
我们在买票的时候,出现了重复买票的问题,还出现了票数为负的问题。
我们可以使用线程的同步解决如上的问题。
java中提供的同步的方式:
1.同步代码块
语法:
synchronized(同步对象){
需要同步的代码
}
2.同步方法:使用synchronized修饰的方法被称为同步方法
访问权限修饰符 【static】 【final】 【synchronized】 返回值类型 方法名称(【参数列表】)【throws 异常...】{}
同步带来最大的好处就是使线程变得安全了。
同步可以保证资源共享操作的正确性,但是需要我们注意的是,同步过多也会产生问题。
需求:现在有两个人一个叫张三,一个叫李四,张三想要李四的画,李四想要张三的书,那么张三对李四说:你把你的画给我,我就给你我的书,李四对张三说:不行,你得先把你的书给我,我就给你我的画。此时,张三等待李四的答复,李四也在等待张三的答复。
我们把以上的这个情况称之为死锁。
所谓的死锁就是指两个线程都在等待对方先执行结束,造成了程序的停滞,一般程序的死锁都在程序运行时出现的。
需要我们注意的就是:多个线程共享同一个资源的时候需要进行同步,以保证资源操作的完整性,但是过多的同步就可能产生死锁。
生产者与消费者问题:
生产者不断的生产,消费者不断的取走生产出来的东西。
需求:生产者生产信息的,信息分为信息的标题以及信息的内容,消费者就是将信息不断的取出,然后打印。
由于线程运行的不确定性,可能会产生以下的问题:
1.假设生产者线程刚向存储空间添加了信息的名称,但是还没有加入信息的内容的时候,程序就切换到消费者运行了,消费者就可能将刚产生的标题,与上一次产生的内容合并成一个信息。
2.生产者放置若干个信息之后,消费者才开始运行,或者消费者刚消费完一个信息,还没等生产呢,又重复的消费了,导致取出相同的信息。
Object类对线程的支持:
wait():让当前的线程等待。
notify():唤醒当前正在等待的线程。
wait()与sleep()方法的区别:
wait():可以让线程进入阻塞的状态,直到调用notify()将其唤醒,否则一直处于阻塞状态。
sleep():可以让线程进入则色状态,当设置的休眠时间一到,线程马上解除阻塞状态。