一,什么是线程?
线程:在一个程序中同时运行的多个独立流程,每一个独立的流程就是一个线程,一个线程相当于的一条运行路径。
二、程序、进程、线程的区别
程序:程序只是一组指令的有序集合,它本身没有任何的运行的含义,只是一个静态的实体。
进程:进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,是系统进行资源调度和分配的一个独立单位。
线程:线程是进程的一个实体,是cpu调度和分配的基本单位,是一条运行路径,它可以与同属于一个进程的线程共享进程所拥有的全部资源,一个进程至少有一个线程。
三、在Java中如何创建线程
在Java中创建线程有三种方式:
1,创建一个类,使他继承Thread类,并重写run()方法;
2,创建一个类,使它实现Runnable接口,并重写run()方法;
3,创建一个类,使它实现Callable接口,并重写call()方法,与其他两种方式不一样的是,call方法有返回值;
具体例子如下图所示:
提示(继承Thread类时,如果没有重写run方法,并不会报错,但实例化后并不会产生线程)
提示(实现Runnable接口时,必须重写run方法,否则会报错,无法编译通过)
提示(实现Callable接口时,必须重写call方法,否则会报错,无法编译通过,call方法有返回值,必须在实现接口的时候就把返回值类型填进去)
四、线程的状态
线程主要有六种状态,每种状态的产生原因与运行状况都不一样;
1,初始状态:线程被实例化后即进入初始状态,这个时候线程刚刚产生,并未运行。
2,可运行状态:通过调用start()方法,线程从初始状态变为可运行状态,注意,这个时候线程并不会运行,而是等待cpu进行调度与分配。(是调用start()方法,不是run()方法,调用run()方法只是普通的方法调用,并不会唤醒线程)
3,运行状态:线程被操作系统选中,从可运行状态转为运行状态,开始执行run()方法。
4,堵塞状态:线程A正在运行时,调用了自身的sleep()方法,进入睡眠,这时候线程A进入阻塞状态.
线程A正在运行时,在A的run()方法中,线程B调用了它的join()方法,这时候A进入堵塞状态
线程A正在运行时,需要调用外界IO设备,这时A进入阻塞状态,等待IO设备准备就绪.
5,锁池状态:线程A执行被synchronized修饰的方法或代码块时,发现线程B已经在执行了,这时,A不会执行这个方法或 代码块,而是进入锁池,然后转为可运行状态,等待下一次cpu的调度。
具体状态图如下所示:
四、线程中常用的方法
sleep():是当前线程(即调用该方法的线程)暂停执行一段时间,让其他线程有机会继续执行,但他不会释放对象锁,该方法会产生异常。
join():使调用此方法的线程在此之前执行完毕(插队先行完成),该方法会产生异常。
yield():该方法与sleep方法类似,只是不能由用户决定暂停多少时间,并且该方法只能让同优先级的线程有执行的机会。
wait():该方法为object的方法,使当前线程暂停执行并释放对象锁,让其他线程可以进入synchronize修饰的数据块中,当前线程被放入等待池
优先级:线程可以通过调用setPriority来改变线程的优先级,优先级越高只是意味着被选中的概率越大。
五、什么是线程并发
当多个线程共同访问同一段代码段,或者一个数据资源时,可能会产生,误读、脏读的现象,这就叫做线程并发。
六、如何进行线程同步
产生线程并发现象时,会造成数据不准确的现象,为了防止这种现象产生,我们可以使用synch(同步锁)关键字,来实现线程同步,synchronize可以修饰一个方法或者一段代码段,当线程A执行被synchronized修饰的方法或代码块时,发现线程B已经在执行了,这时,A不会执行这个方法或 代码块,而是进入锁池,然后转为可运行状态,等待下一次cpu的调度。这样就可实现线程同步了,其实就是多个线程访问的时候,给他们排排队,不允许同时对数据资源进行操作。