多线程--java
多线程
单核cpu没有并行,它只不过是CPU时钟调度给你错觉,让你误以为他们真的在同一时间同时运行。
多核cpu才有并行
每一个task就是一个进程(Process), 在每一个process中至少有一个线程(Thread)在运行, 有时线程也称为轻量级的进程
每个thread , 都有自己的局部变量表,程序计数器以及各自的生命周期
java每创建一个Thread就创建一个线程,java创建的线程默认是处于非阻塞状态,异步通信机制,以及线程内存共享
下面是一个简单的并行,sayhi(),sayno()为两个静态方法,下面有两个线程,一个lambada表达式,一个是main
syano也是如此,添加sleep(100)的原因是 10个for循环可能就是一毫米的事情
private static void sayhi(){ for(int i=0;i<10;i++){ System.out.println("hi"); try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
阻塞非阻塞是程序等待调用结果的状态
阻塞调用: 没立即得到结果,当前线程会被挂起 ,也就是处于阻塞状态
非阻塞调用:没立即得到结果,不会阻塞当前线程
同步异步是消息通信机制
同步: 等阻塞调用得到返回结果后,才返回I/O系统
异步:因为不阻塞当前线程,立即返回I/O系统,CPU可以去处理其它线程,等收到返回结果后,再去处理该线程
默认都是非阻塞调用,异步通信机制,因为它可以大大提高CPU性能。
为了更高效地减小线程的开销,多个线程可以对同一个内存资源共享调用,但会造成线程不安全
线程不安全:(多线程和单线程运行的结果不一样)
解释: 多线程调用与单线程(加锁)调用相同内存资源的结果不一样
线程安全:(每次运行的结果和单线程运行的结果是不一样的,而且其他的变量的值也和预期的是一样的)
加锁,通过加synchronized ,使某程序不能内存共享,阻塞调用,异步通信机制,所以对相同内存只能单线程运行。
注意:对不同内存资源是多线程。
也就是说加锁只对于线程访问相同内存资源,对于访问不同的内存资源不影响
对线程访问同一个内存资源代码不加锁
对线程访问同一内存资源加锁
对同一内存资源可以是 方法,代码块,对象
synchronized 修饰方法
如上图所示
synchronized 修饰代码块
synchronized(this){ //**代码块**// }
synchronized 修饰对象
synchronized(MultiThreading.class){ }
synchronized(对象名){
}
线程的五种状态
创建状态 NEW
创建了线程对象,已经有相应的内存空间,但处于不可运行状态。 例如:Thread thread=new Thread()
就绪状态 RUNNABLE
启动了线程,也就是 start(),已经在JVM中创建了线程,但是还在等待CPU的调度 (线程的运行都听从于CPU的调度)
运行状态 RUNNING
线程获得CPU的执行,注意线程只能从runnable 到 running
在该状态中,可以发生如下转换:
- 直接进入TERMINATED状态, 比如已经弃用的stop(),判断中断标识来判断是否中断线程interrupt()
- 进入BOLOCKED状态,比如调用了sleep, wait方法,进行某个阻塞的IO操作,获得某个锁资源
- 进入RUNNABLE状态, 比如由于CPU的调度器轮询使该线程放弃执行, 线程主动调用yield方法,放弃CPU执行权
阻塞状态 BOLOCKED
该线程处于阻塞状态。sleep() , suspend(), wait()等会使线程进入阻塞状态,直到过了sleep()时间,调用resume(),调用notify()等
在该状态下可切换至如下几个状态:
- 直接进入TERMINATED状态
- 线程阻塞状态结束,比如过了sleep()时间,notify/notifyall唤醒等进入RUNNABLE状态
TERMINATED
一个线程的最终状态
suspend() 与 resume() 暂停与暂停后继续
run()中加入suspend(),程序运行到suspend()后,线程中断,进入阻塞状态,等到线程对象调用sleep()与resume()后,线程继续
suspend()不会释放所持锁,如果resume()在suspend()之前,会造成死锁,已弃用
//i==3时会停一秒钟,再输出3,4,5
//如果注释掉resume(),程序将输出1,2 然后一直处于等待状态
public class MultiThreading implements Runnable{ @Override public synchronized void run() { for (int i = 1; i <= 5; i++) { if (i ==3) { Thread.currentThread().suspend(); } System.out.println(String.format("i:%s 线程:%s", i, Thread.currentThread().getName())); } } public static void main(String args[]) throws InterruptedException { MultiThreading a = new MultiThreading(); Thread one = new Thread(a); one.start(); Thread.sleep(1000); one.resume(); } }
wite() 与 notify()
wait() 与 notify() 必须要在相同对象锁下调用(在synchronized(){}内调用),不然会抛出java.lang.IllegalMonitorStateException的异常
synchronized(this) 指当前对象, synchronized(对象) 指该对象锁
wait()与notify()是Object对象就有的,也就是说所有对象都有
调用wait() 会释放该锁,该线程进入阻塞,但是其它线程可以接管该锁; 不同于suspend() ,suspend()不会释放锁,线程会一直挂在那并且其它线程无法继续访问与它的相同内存资源,直到等到resume();
wait()相比于suspend()不会造成死锁
join()
等待该线程完成后,才能继续运行join()之后的程序
加锁下输出1~10
public class MultiThreading implements Runnable{ public synchronized void run() { int i=1; while(i<10) { i++; } } public static void main(String[] args) { MultiThreading a = new MultiThreading(); Thread threadOne = new Thread(a); Thread threadTwo = new Thread(a); threadOne.start(); threadTwo.start(); } }
结果是1 2 3 4 5 6 7 8 9 1 2 3 4 5 6 7 8 9
它只能先执行完threadOne ,然后再执行threadtwo
加锁并加wait()与notify() 使输出结果为 112233445566778899
public class MultiThreading implements Runnable{ public synchronized void run() { int i=1; while(i<10) { this.notifyAll(); try { this.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(i); i++; } this.notifyAll(); } public static void main(String[] args) { MultiThreading a = new MultiThreading(); Thread threadOne = new Thread(a); Thread threadTwo = new Thread(a); threadOne.start(); threadTwo.start(); } }
通过往实现的Runnable接口的类 加入对象锁 Object lock ,
实现多个线程的调度
如下是输出 1212121212121212
public class MultiThreading implements Runnable{ private int num; private Object lock; public MultiThreading(int num,Object lock) { this.num = num; this.lock=lock; } public void run() { synchronized(lock) { int i=1; while(i<10) { lock.notifyAll(); try { lock.wait(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(num); i++; } lock.notifyAll(); } } public static void main(String[] args) { Object lock =new Object(); MultiThreading a_one = new MultiThreading(1,lock); MultiThreading a_two = new MultiThreading(2,lock); Thread threadOne = new Thread(a_one); Thread threadTwo = new Thread(a_two); threadOne.start(); threadTwo.start(); } }
不加wait()与notify()的结果是 先执行完线程threadOne,后执行threadTwo