实现线程并发有两种方式:1)继承Thread类;2)实现Runnable接口。
- 线程基础
1)程序、进程、线程;并行、并发。
2)线程生命周期:创建状态(new一个线程对象)、就绪状态(调用该对象的start()方法)、执行状态(run()方法体的执行)、阻塞状态(sleep()/wait()方法的调用)、终止状态(destroy()/stop()非正常结束、或、run()方法体跑完后正常结束)。 另外从阻塞状态到执行状态,可用方法notify()/notifyAll()。
- 定义自己的线程——继承Thread类
在Java里实现多线程,只需要我们继承Thread类,并且覆写run()方法来执行我们想要的逻辑代码即可,仅此而已!
public class MyThread extends Thread{...public void run(){...}...} Thread t=new MyThread(i);//创建状态 t.start();//就绪状态,start()方法会自动触发t对象的run()方法体的执行,从而进入执行状态;但是,至于什么时候执行、线程之间的执行顺序都是不可预测的了,完全有OS决定。
- 解决继承局限性(单继承)——实现Runnable接口
1)通过继承Thread类,可以实现多线程并发;但是由于Java的单继承,使得MyThread类不能再继承其他的父类。
2)可以通过实现Runnable接口的方法,这样不仅能够满足多线程并发,还能满足继承其它父类。
class Parent{...} public class MyThread extends Parent implements Runnable{...public void run(){...}...} Thread t=new Thread(new MyThread(i));//先实例化自定义类MyThread的对象,再通过该对象作为参数实例化Thread对象 t.start();//进而调用Thread对象的start()方法
- 控制多线程并发
1)sleep()方法——让线程休眠
try{ sleep(2000); }catch(InterruptedException e){...}//sleep()方法会抛出异常,所以要catch处理。
注意:sleep()方法在线程阻塞的过程中,并不释放自己已经占用的资源;所以说,sleep()虽然可以提高CPU资源利用率,但是也会增加发生死锁的可能性!
2)通过synchronized关键字声明同步,实现对临界资源的互斥访问
2.1)对访问互斥资源的方法添加synchronized关键字,实现互斥访问————synchronized方法
class SynObj{ public synchronized void synAdd(){a--...i++...} public synchronized void synMinus(){...i--...b++} }//每当线程调用用synchronized修饰的同步方法时,就获得了当前对象SynObj的锁资源,此时其他线程就不能再调用这个对象SynObj的同步方法了。
2.2)对访问互斥资源的方法添加synchronized关键字的缺陷是,a--,b++这些非互斥的资源也不能访问了。所以Java还提供了更好的方法————synchronized块
class SynObj{ Object o=new Object(); public void synAdd(){a--... synchronized(o){i++}...} public void synMinus(){...synchronized(o){i--}...b++} }//synchronized块通过指定一个无意义的新对象作为同步的令牌,而不是使用当前对象SynObj本身,这就保证了不用在方法的整个过程锁住SynObj对象,而只要在真正访问互斥资源的逻辑代码段锁住对象即可。
3)sleep()、wait()、notify()、notifyAll()
sleep():来自Thread类。sleep()方法在线程阻塞的过程中,并不释放自己已经占用的资源。
wait():来自Java类的父类Object类,由notify()唤醒。wait()方法在线程阻塞的过程中,会释放自己已经占用的资源。
notify():随机从因为wait()方法而被阻塞的多个线程中选择一个唤醒,至于选择哪一个是无法预测的。
notifyAll():
4)产生死锁的原因:多个进程竞争临界资源;进程推进顺序不当。
5)Java把线程分为10个优先级別,分别用1-10表示;数字越小优先级别越高,表示该线程运行的逻辑越紧要,系统会分配更多的CPU时间给高优先级线程(注意,不是一定先运行)。通过setPriority(i)、getPriority()来对优先级进行存取。