多线程java
Java的特色之一就是线程的处理较为简单。安全
通常操做系统都支持同时运行多个任务,一个任务一般就是一个程序,每一个运行中的程序被称为一个进程,每一个顺序执行流就是一个线程。多线程
进程:正在运行的程序,是程序动态的执行过程(运行内存中)。并发
线程:在进程内部,并发运行的过程。对于一个程序而言,可能同时运行多个任务,那么每一个任务称为一个线程。app
并发:进程是并发运行的,OS将时间划分为不少时间片断(时间片),尽量均匀分配给正在运行的程序,微观上进程走走停停,宏观上都在运行,这种都运行的现象叫并发,可是不是绝对意义上的“同时发生”。异步
一、Thread类ide
Thread类表明线程类型。函数
咱们调用start()方法时候,该线程会想线程调度注册当前线程。只有注册了,才有机会被分配时间片进行并发运行。高并发
不能调用run方法,若是调用了,就不是并发运行了,就变成同步了。有前后顺序执行。ui
时间片是不均匀的,每一个线程分配时间不是相等的。线程调度机制尽量均匀的将时间片断分配给不一样线程,让他们都有机会的到cpu的运行。分配给谁的时间片断是不可控的。
stop()方法,关闭线程,因为具备不安全性,不建议使用。
正常的线程中止方法是让run()方法正常的执行完毕。
线程运行过程当中,若出现该类未捕获异常,该线程马上终止。可是不会影响当前进程中其余线程的工做。
若当前进程中全部线程都终止了,那么进程终止。
建立线程的另外一种方式将线程与线程体分开,做为线程体就是线程要并发执行的逻辑。最好的模式应该是线程只关心并发操做,不关心具体并发作的事情,咱们应该将线程与线程体自己解耦。
例子:
public static void main(String[] args) { /** * Thread 类 * Thread类的一个实例表明一个线程 * 咱们能够经过继承Thread并重写run方法,来完成咱们想并发的代码。 */ Thread thread1 = new NumThread(); Thread thread2 = new HelloWordThread(); /** * 不能调用run方法, */ thread1.start(); thread2.start(); } /** * 建立一个并发任务 * 重写run方法来编写并发任务代码。 */ public static class NumThread extends Thread{ @Override public void run() { for (int i = 0; i < 10000; i++) { System.out.println(i); } }
二、Runnable实现线程
建立一个实现Runnable接口,重写run方法,以实现了Runnable接口的类的实例对象做为建立Thread类对象的构造函数的参数。
public static void main(String[] args) { //建立要并发执行的逻辑再交给线程去 Thread th = new Thread(new HooThread()); th.start(); } public static class HooThread implements Runnable{ public void run(){ for (int i = 0; i < 10000; i++) { System.out.println("how are you"); } } }
可是这里经常使用内部类。
new Thread(new Runnable(){
public void run(){...}
}).start();
这种方式将线程体和线程分离开,咱们就能够最大程度的利用线程,有了这个思想,就有了后面的线程池的应用。
三、线程的生命周期
线程一旦结束,不能再次调用start()方法。、
相关方法:
static void yield()当前现横让出处理器(离开Running状态),使当前线程进入Runnable状态等待,等待下次分配时间片。
static void sleep(times)让线程从Running状态进入block状态,阻塞times好秒后自动回到Runnable状态。
若是在block时,其余线程打断当前线程的Block(sleep)就会发生异常InterruptedException.
void interrupt()中断线程。
final void setPriority(int)改变线程的优先级。
final void join()等待该线程终止。
/** * 电子表功能 * 思路: * 1.获取系统时间 * 2.每秒输出一次 */ SimpleDateFormat format=new SimpleDateFormat("hh:mm:ss"); while(true){ Date date = new Date(); String s = format.format(date); System.out.println(s); Thread.sleep(1000); }
一个例子:模拟一个节目的砸墙
public static void main(String[] args) { /** * 砸墙 * t1线程:林永健 处理睡眠阻塞的线程 * t2线程:黄宏 用于打断t1睡眠阻塞的线程 */ final Thread lin = new Thread(){ public void run() { System.out.println("林:睡觉去了"); try { Thread.sleep(10000000); } catch (InterruptedException e) { //e.printStackTrace(); System.out.println("林:干吗呢?都破了相了!"); } } }; lin.start(); Thread hang = new Thread(){ public void run() { System.out.println("黄:准备砸墙!"); for (int i = 9; i >0; i--) { System.out.println("黄:"+(10*i)); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("黄:搞定!"); /** * 打断t1的睡眠阻塞 */ lin.interrupt();//中断线程 } }; hang.start(); }
四、线程的优先级
线程的优先级根据数字划分为10个等级。
1最小 对应的常量是 MIN_PRIORIITY
10最大 对应的常量是 MAX_PRIORIITY
默认是5 对应的常量是 NORM_PRIORIITY
//设置优先级
t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(1);
不是绝对的,但大多状况是这样,毕竟线程分配调度的时间片不可控。
五、守护线程
又叫后台线程,特色:当进程中全部前台线程都终止后,守护线程强制终止。
当进程中只有守护线程时,Java虚拟机退出,进程也终止了。
后台线程是在线程启动前经过方法设置的。
setDaemo(boolean) 当参数是true时,该线程是后台线程。必须在线程启动以前设置,不然没有用了。
//守护线程,要在start以前设置。
jack.setDaemon(true);
六、线程同步的概念
线程同步,能够理解为线程A和B是一块配合,A执行到必定程度时要依靠B的某个结果,因而停下来,示意B执行;B依言执行,在将结果给A;A再继续操做。
所谓同步,就是在发出一个功能调用时,在没有获得结果以前,该调用就不返回,同时其它线程也不能调用这个方法。
1)异步 并发,各干本身的。
2)同步 步调一致的处理,多个线程不能同时访问。
这里就引起出一个关键字 Synchronized
多线程并发读写同一个临界资源时发生“线程并发安全问题”
可使用同步代码快解决线程并发安全问题。
synchronized(同步监视器){}
能够修饰一个方法也能够以独立的代码快存在。
同步监视器:是一个任意对象实例,是一个多个线程之间的互斥的锁机制,多个线程要使用同一个“监视器”对象实现同步互斥。
常见的写法:synchronized(this){} 尽可能减小同步范围,提升并发效率。
synchronized修饰的方法,当一个线程进入到该方法后,会对当前方法所属的对象枷锁。其它线程在访问这个方法时候,发现被锁上了,就在方法外等待,直到对象上的锁被释放为止。
七、线程安全类与线程不安全类
StringBuffer是同步的 synchronized append();
StringBuilder不是同步的 append();
Vector/HashTable是同步的。
ArrayList/HashMap不是同步的。
若是把一个不是同不的集合变成同步的集,可使用
Collections.synchronizedList();
Collections.synchronizedMap();
具体例子以下:
ArrayList list = new ArrayList();
List syncList = Collections.synchronizedList(list);
这样就获得线程安全的集合
也能够直接用
Collections.synchronizedList();
Collections.synchronizedMap();
Collections.synchronizedSet();
获得线程安全的集合。
八、wait和notify简介
属于Object中的方法,用于多线程之间须要协同工做(等待和唤醒)。
就是说:若是条件不知足时,则等待。当条件知足时,等待该条件的线程将被唤醒。在Java中,这个本身的实现依赖于wait/notify.等待机制与锁的机制是密切关联的。
当线程A调用了B对象的wait方法,那么该线程就在B对象上等待。A线程就进入了wait阻塞。若是线程C也调用了B的wait方法,那么该线程也在B对象上等待。当B调用了notify方法,那个A或者B随机一个进入了Runnable状态开始运行,另外一个任然处于wait阻塞。
notifyAll()方法可让等待的全部线程进入Runnable。