1)进程和线程的区别java
进程: 程序运行后,一个QQ,微信等就是一个进程。 线程: 线程是进程中的最小单元。说简单的话说,线程就是程序中不一样的执行路径。 程序: QQ是一个程序,是一个硬盘上的程序,
2)线程run方法和start方法的区别segmentfault
public class T01_WhatIsThread { //新建了静态内部类继承Thrread,线程修改1秒,输入T1 private static class T1 extends Thread { @Override public void run() { for(int i=0; i<10; i++) { try { TimeUnit.MICROSECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("T1"); } } } //main方法 public static void main(String[] args) { new T1().run(); //new T1().start(); for(int i=0; i<10; i++) { try { TimeUnit.MICROSECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("main"); } } } 输出 T1 T1 main main //这个时候注释18run方法 开始start方法 执行结果大不同 T1 main T1 main #结论 therad的start方法 执行路径是分支的形式,而run方法是重上到下依次执行。
3)多线程的经常使用实现方法安全
//线程主要实现的方法有3种 public class T02_HowToCreateThread { //集成Thread的方法 static class MyThread extends Thread { @Override public void run() { System.out.println("Hello MyThread!"); } } //实现Runnable接口 static class MyRun implements Runnable { @Override public void run() { System.out.println("Hello MyRun!"); } } //三种线程不一样的运行方式 public static void main(String[] args) { new MyThread().start(); new Thread(new MyRun()).start(); //lamda表达式来执行一个线程 new Thread(()->{ System.out.println("Hello Lambda!"); }).start(); } } // lamda表达式也是一种方式,线程池也是一种方式 //Executors.newCachedThreadPool(); //经过线程池去拿到一个线程,而这个线程仍是要执行runable或者start的方法。
4)线程最基本的方法微信
4.1 sleep多线程
4.2 joinide
//测试join线程 static void testJoin() { Thread t1 = new Thread(()->{ //线程1建立了10个线程 for(int i=0; i<10; i++) { System.out.println("A" + i); try { //每一个线程休眠500毫秒 Thread.sleep(500); //TimeUnit.Milliseconds.sleep(500) } catch (InterruptedException e) { e.printStackTrace(); } } }); //线程2 Thread t2 = new Thread(()->{ try { //线程1的线程加入。等待线程1结束 t1.join(); } catch (InterruptedException e) { e.printStackTrace(); } //线程1结束后,才开始执行此代码 for(int i=0; i<10; i++) { System.out.println("B" + i); try { Thread.sleep(500); //TimeUnit.Milliseconds.sleep(500) } catch (InterruptedException e) { e.printStackTrace(); } } }); //分别启动 t1.start(); t2.start(); } #执行结果 A0 A1 A2 A3 A4 A5 A6 A7 A8 A9 B0 B1 B2 B3 B4 B5 B6 B7 B8 B9
4.3 yield学习
对于interrupt的一些说明:测试
#线程经过wait()进入阻塞状态,此时经过interrupt()中断该线程; #调用interrupt()会当即将线程的中断标记设为“true”,可是因为线程处于阻塞状态,因此该“中断标记”会当即被清除为“false”,同时,会产生一个InterruptedException的异常。 #咱们会catch这个异常,再根据业务逻辑去处理线程的后续行为。 #代码示例 @Override public void run() { try { // 1. isInterrupted()保证,只要中断标记为true就终止线程。 while (!isInterrupted()) { // 执行任务... } } catch (InterruptedException ie) { // 2. InterruptedException异常保证,当InterruptedException异常产生时,线程被终止。 } } //interrupt 用于控制业务场景的用法极少,正经常使用法通常是某一个线程阻塞时间很长很长,经过interrupt来打断线程。
线程状态的小例子this
static class MyThread extends Thread { @Override public void run() { System.out.println(this.getState()); for(int i=0; i<4; i++) { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(i); } } } public static void main(String[] args) { Thread t = new MyThread(); System.out.println(t.getState()); t.start(); try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(t.getState()); } #输出结果 NEW RUNNABLE 0 1 2 3 TERMINATED
须要注意的是 锁,所的是对象,而不是代码spa
好比:
public class T { private int count = 10; private Object o = new Object(); public void m() { synchronized(o) { // **任何线程要执行下面的代码,必须先拿到o的锁** count--; System.out.println(Thread.currentThread().getName() + " count = " + count); } } } #问题 上述代码若是new了2个不一样的object,o和o1,那synchronize(o) 是锁誰呢,固然锁o。 ```
synchronize 的几种锁的形式
锁this
private int count = 10; public void m() { synchronized(this) { //任何线程要执行下面的代码,必须先拿到this的锁 count--; System.out.println(Thread.currentThread().getName() + " count = " + count); } }
锁方法
private int count = 10; public synchronized void m() { //等同于在方法的代码执行时要synchronized(this) count--; System.out.println(Thread.currentThread().getName() + " count = " + count); }
锁静态方法
private static int count = 10; public synchronized static void m() { //这里等同于synchronized(T.class) count--; System.out.println(Thread.currentThread().getName() + " count = " + count); } public static void mm() { synchronized(T.class) { //考虑一下这里写synchronized(this)是否能够?(不可,由于没有new,) count --; } }
小思考
1) 下面的线程如何输出? 2)加上synchronize后又有什么区别 3)加上volatile后又什么区别
private /*volatile*/ int count = 100; public /*synchronized*/ void run() { count--; System.out.println(Thread.currentThread().getName() + " count = " + count); } public static void main(String[] args) { T t = new T(); for(int i=0; i<100; i++) { new Thread(t, "THREAD" + i).start(); } } #1 打印列会出现重复或者实际减的数和打印的数不一致。 //打印结果抽取异常部分 THREAD81 count = 37 THREAD70 count = 37 #2 synchronize 既保证可见又保证一致性 #3 volatile 保证可见性,这个变量改后立马被线程发现。 #4 加了synchronize就没必要加volatile。
$\color{red}{程序若是出现异常,默认状况下锁会被释放}$
public class T { int count = 0; synchronized void m() { System.out.println(Thread.currentThread().getName() + " start"); while(true) { count ++; System.out.println(Thread.currentThread().getName() + " count = " + count); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } if(count == 5) { int i = 1/0; //此处抛出异常,锁将被释放,要想不被释放,能够在这里进行catch,而后让循环继续 System.out.println(i); } } } }} public static void main(String[] args) { T t = new T(); Runnable r = new Runnable() { @Override public void run() { t.m(); } }; new Thread(r, "t1").start(); try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } new Thread(r, "t2").start(); } } #//打印结果 人为异常不补货,t2获得锁。继续执行 t1 count = 2 t1 count = 3 t1 count = 4 t1 count = 5 t2 start Exception in thread "t1" t2 count = 6 java.lang.ArithmeticException: / by zero at com.mashibing.juc.c_011.T.m(T.java:27) at com.mashibing.juc.c_011.T$1.run(T.java:39) at java.base/java.lang.Thread.run(Thread.java:844) t2 count = 7
推荐文章 锁升级的小段子
偏向锁(谁来谁第一,谁偏向)----》
竞争 自旋锁,(自旋10次或者 JDK目前规定为自旋线程超过CPU内核数的一半)
若是超过了自旋的上限,就升级重量级锁,重锁是OS(操做系统)级别的锁,并进入等待队列。
锁使用的场景:
$\color{red}{线程少,上锁代码执行快,用自旋锁}$ $\color{red}{线程多,上锁代码执行长,用OS重量锁}$