1.首先java多线程的实现方法主要是两种;一种就是集成Thread类,另一种就是实现runnable接口.
2.多线程的几种状态:
新建状态----也就是创建线程对象
就绪状态----当调用线程对象的start()方法,线程就进入就绪状态
运行状态----当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态
阻塞状态----处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行;
死亡状态----死亡状态:就是线程执行完毕或出现异常退出了run方法
说明:阻塞状态又分为,等待阻塞,同步阻塞,以及其他阻塞。其中等待阻塞也就是运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;
同步阻塞也就是线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;其他阻塞也就是通过调用线程的sleep()或join()或发出了I/O请求时,
线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
3.Runnable接口与Thread类分别实现多线程的区别:
首先通过实现Runnable接口来开启多线程:
package com.julong.thread; public class RunableTest { /** * @Author email: * @data 2017-4-27 * @version 1.0.1 * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Thread2 my = new Thread2(); new Thread(my, "C").start();//同一个my,但是在Thread中就不可以,如果用同一个实例化对象mt,就会出现异常 new Thread(my, "D").start(); new Thread(my, "E").start(); } } class Thread2 implements Runnable{ private int count=15; @Override public void run() { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + "运行 count= " + count--); try { Thread.sleep((int) Math.random() * 10); } catch (InterruptedException e) { e.printStackTrace(); } } } }
通过继承Thread类来开启多线程:
package com.julong.thread; public class ThreadTest2 { /** * @Author * @data 2017-4-27 * @version 1.0.1 * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Thread3 mTh1=new Thread3("A"); Thread3 mTh2=new Thread3("B"); mTh1.start(); mTh2.start(); } } class Thread3 extends Thread{ private int count=5; private String name; public Thread3(String name) { this.name=name; } public void run() { for (int i = 0; i < 5; i++) { System.out.println(name + "运行 count= " + count--); try { sleep((int) Math.random() * 10); } catch (InterruptedException e) { e.printStackTrace(); } } } }
通过对比两者可以发现当要通过多个线程去处理同一资源时只能通过Runnable来实现,Runnable接口可以避免java类单继承的缺点,使得增加程序的健壮性,代码可以被多个线程共享,代码和数据独立
4.多线程中常用的方法:
sleep()-----让当前正在执行的线程休眠,在休眠时间内不被执行,等待休眠时间结束之后才回到可执行状态,
wait()----wait就是说线程在获取对象锁后,主动释放对象锁,同时本线程休眠, 直到有其它线程调用对象的notify()唤醒该线程,才能继续获取对象锁
notify()----唤醒处于等待状态的线程
join()---当有主线程和子线程一起执行时,通过join可以控制主线程等待子线程执行终止
yield()---使当前线程回到可执行状态,并选取其他同等优先级或更高优先级的线程执行,也有可能立刻就执行它自己,不可能执行优先级比他低的线程
interrupt---终端某个线程
5.线程的同步:
线程的同步主要用到synchronized关键字同步锁,用于将某段代码变为同步操作,从而解决线程并发安全问题分为同步方法和同步代码块。采用线程同步的一般规则
1、如果两个或两个以上的线程都修改一个对象,那么把执行修改的方法定义为被同步的,如果对象更新影响到只读方法,那么只读方法也要定义成同步的。
2、不要滥用同步。如果在一个对象内的不同的方法访问的不是同一个数据,就不要将方法设置为synchronized的
3、如果一个线程必须等待一个对象状态发生变化,那么他应该在对象内部等待,而不是在外部。他可以通过调用一个被同步的方法,并让这个方法调用wait()。
4、每当一个方法返回某个对象的锁时,它应当调用notifyAll()来让等待队列中的其他线程有机会执行。
5、记住wait()和notify()/notifyAll()是Object类方法,而不是Thread类的方法。仔细查看每次调用wait()方法,都有相应的notify()/notifyAll()方法,且它们均作用于同一个对象。