一、注解

方法重写时常见
image.png

二、多线程

1、什么是多线程

1、概念:如果在一个进程中同时运行了多个线程,用来完成不同的工作,则称之为“多线程” 多个线程交替占用CPU资源,而非真正的并行执行

2、多线程的好处

(1)、充分利用CPU资源
(2)、简化编程模型
(3)、用户体验度较高
3、main也是多线程的一种———主线程

4、创建线程的两种方式

1、继承 Thread类
2 、实现Runnable 接口
3、定义MyThread类继承Thread类 重写run()方法,编写线程执行体 创建线程对象,调用start()方法启动线程
其中包含 : 获得当前线程名字 Thread.currentThread().getName()
让线程休息100毫秒Thread.sleep(100);
创建线程Thread t1=new LianXi1();
启动线程t1.start();
优先级t1.setPriority(MAX_PRIORITY);
阻断线程join()

  1. public class LianXi1 extends Thread {
  2. /*
  3. * 继承Thread类实现多线程
  4. */
  5. public void run(){
  6. for (int i = 0; i < 100; i++) {
  7. //获得当前线程的名字 Thread-0
  8. Thread t=Thread.currentThread();
  9. System.out.println(t.getName()+"----"+i);
  10. try {
  11. //让线程休息100毫秒
  12. Thread.sleep(100);
  13. } catch (InterruptedException e) {
  14. e.printStackTrace();
  15. }
  16. }
  17. }
  18. public static void main(String[] args) {
  19. //创建线程
  20. Thread t1=new LianXi1();//Thread-0
  21. Thread t2=new LianXi1();//Thread-1
  22. // Thread t3=new LianXi1();//Thread-2
  23. //启动线程执行run方法
  24. t1.start();
  25. // t2.start();
  26. // t3.start();
  27. //设置优先级 //设置线程的优先级Thread.MAX_PRIORITY==10;
  28. //优先级越高,获得CPU资源的概率越高
  29. // t1.setPriority(MAX_PRIORITY);//10
  30. // t2.setPriority(MIN_PRIORITY);//1
  31. // t3.setPriority(NORM_PRIORITY);//5
  32. //阻断线程
  33. for (int i = 0; i <10; i++) {
  34. if(i==5){
  35. try {
  36. //阻断线程,谁调join谁先执行
  37. /*
  38. * 主线程和t1线程先交替进行,当i=5时,主线程停止运行
  39. * 此时t1线程仍会执行到100,然后main线程再继续执行
  40. */
  41. t1.join();
  42. } catch (InterruptedException e) {
  43. e.printStackTrace();
  44. }
  45. }
  46. //输出当前线程名
  47. System.out.println(Thread.currentThread().getName()+"====="+i);
  48. try {
  49. Thread.sleep(1000);
  50. } catch (InterruptedException e) {
  51. e.printStackTrace();
  52. }
  53. }
  54. }

4、定义MyRunnable类实现Runnable接口 实现run()方法,编写线程执行体 创建线程对象,调用start()方法启动线程

  1. //实现Runnable接口,实现多线程
  2. public class LianXi2 implements Runnable {
  3. @Override
  4. public void run() {
  5. for (int i = 0; i < 100; i++) {
  6. Thread t=Thread.currentThread();
  7. System.out.println(t.getName()+"---"+i);
  8. }
  9. }
  10. public static void main(String[] args) {
  11. Thread t1=new Thread(new LianXi2());
  12. Thread t2=new Thread(new LianXi2());
  13. t1.start();
  14. t2.start();
  15. }

5、两种创建线程的区别
继承Thread类 编写简单,可直接操作线程 适用于单继承 ;实现Runnable接口 避免单继承局限性 便于共享资源

5、创建线程的另一种方式(了解)

继承Callable接口

  1. public class LianXi4 implements Callable<String> {
  2. /*
  3. * 实现Callable<String>接口实现多线程
  4. */
  5. public static void main(String[] args) {
  6. LianXi4 lx=new LianXi4();
  7. FutureTask<String> ft=new FutureTask<String>(lx);
  8. Thread t=new Thread(ft);
  9. t.start();
  10. try {
  11. //可以得到回复通知
  12. System.out.println(ft.get());
  13. } catch (InterruptedException e) {
  14. e.printStackTrace();
  15. } catch (ExecutionException e) {
  16. e.printStackTrace();
  17. }
  18. }
  19. @Override
  20. public String call() throws Exception {
  21. for (int i = 0; i < 100; i++) {
  22. System.out.println(Thread.currentThread().getName()+"---"+i);
  23. }
  24. return "ok";
  25. }

6、创建线程有哪几种方式?

继承java.lang.Thread类 实现java.lang.Runnable接口

7、如何启动线程?

先创建,再用变量名.start();启动线程

8、线程对象调用start()方法和调用run()方法的区别?

start()方法来启动线程,真正实现了多线程运行,跟其他线程交替执行;run()方法当作普通方法的方式调用,程序还是要顺序执行

9、线程的5种状态

创建状态,就绪状态,运行状态,死亡状态,阻塞状态
image.png

10、线程的调度

使用方法见Thread线程
image.png

11、什么是优先级?在线程调度中的作用?

线程优先级由1~10表示,1最低,默认优先级为5;优先级高的线程获得CPU资源的概率较大

12、join()方法和yield()方法的区别是什么?

join()阻塞,阻塞父线程,使当前线程暂停执行,等待其他线程结束后再继续执行本线程;塞阻塞主线程,子线程强制执行主线;yield()暂停当前线程,线程处于就绪状态,不转为阻塞状态程,子线程强制执行

13、练习:看病叫号

  1. public class CureThread implements Runnable {
  2. Object obj = null;
  3. public CureThread(Object obj){
  4. super();
  5. this.obj = obj;
  6. }
  7. @Override
  8. public void run() {
  9. //模拟特需号看病
  10. for(int i = 1 ;i <= 10; i++){
  11. synchronized (obj) {
  12. System.out.println(Thread.currentThread().getName()
  13. + i +"号人在看病");
  14. try {
  15. Thread.sleep(4000);
  16. } catch (InterruptedException e) {
  17. e.printStackTrace();
  18. }
  19. }
  20. }
  21. }
  22. public class CureThreadTest {
  23. static Object obj = new Object();
  24. public static void main(String[] args) {
  25. Thread t1 = new Thread(new CureThread(obj),"特需号");
  26. t1.setPriority(Thread.MAX_PRIORITY);
  27. //t1.setName("特需号");
  28. t1.start();
  29. //主线程模拟普通号
  30. Thread.currentThread().setName("普通号");
  31. for(int i = 1; i <= 50;i++){
  32. synchronized (obj) {
  33. System.out.println(Thread.currentThread().getName() + i +
  34. "号人在看病");
  35. try {
  36. Thread.sleep(2000);
  37. } catch (InterruptedException e) {
  38. e.printStackTrace();
  39. }
  40. if (i==10) {
  41. try {
  42. t1.join();
  43. } catch (InterruptedException e) {
  44. e.printStackTrace();
  45. }
  46. }
  47. }
  48. }
  49. }

三、锁

1、synchronized java关键字

2、为什么要线程同步?

多个线程操作同一共享资源时,将引发数据不安全问题

3、线程同步的两种方式?

(1)、访问修饰符+synchronized
(2)、synchronized 代码块

4、线程安全和线程不安全?

image.png
5、lock和synchronized的区别?
synchronized是关键字;1.8优化后,锁升级(偏向锁—>轻量级锁/(CAS)自旋锁—>重量级锁),不可逆的
* lock是java的类/接口;手动加锁手动释放,因为syn不可逆

  1. //线程非安全
  2. ArrayList list=new ArrayList();
  3. //线程安全的
  4. Vector vector=new Vector();
  5. //※考点安全非安全对比,和是否存入null???
  6. //线程非安全的(key和value均可以为null)
  7. HashMap map1=new HashMap();
  8. map1.put(null, null);
  9. //线程安全的,底层源码加了锁同步方法,维度更大,控制value为null,会抛出空指针异常
  10. Hashtable map2=new Hashtable();
  11. map2.put(null, null);
  12. //线程安全的;1.7采用的是分段锁机制,1.8自旋锁-->synchronized代码块 ,效率更高
  13. //key或value为null,会抛出空指针异常
  14. ConcurrentHashMap map3=new ConcurrentHashMap();
  15. map3.put(null, null);
  16. //线程非安全的
  17. StringBuilder sb2=new StringBuilder();
  18. //线程安全的 ,源码方法加了synchronized修饰
  19. StringBuffer sb1=new StringBuffer();
  20. }

6、练习,抢票系统

image.png

  1. /*
  2. * 有10张票。没卖出一张就记上
  3. */
  4. public class SaleTicket implements Runnable{
  5. //已经售卖的票数
  6. int saleNum=0;
  7. int count=10;//总票数
  8. @Override
  9. public void run() {
  10. while(sale()){
  11. }
  12. }
  13. //synchronized java关键字,
  14. /*
  15. * 1、修饰方法,方法叫同步方法,给方法加锁
  16. * 2、同步代码块,可以锁局部,可以降低锁的粒度/维度,提高运行效率
  17. * lock和synchronized的区别
  18. * synchronized是关键字;1.8优化后,锁升级(偏向锁-->轻量级锁/(CAS)自旋锁-->重量级锁),不可逆的
  19. * lock是java的类/接口;手动加锁手动释放,因为syn不可逆
  20. *
  21. * 不加wait()和notify()也能实现
  22. */
  23. private boolean sale(){//什么时候卖完什么时候跳出
  24. synchronized (this) {
  25. //唤醒等待队列的线程
  26. // notify();
  27. if(count<=0){
  28. System.out.println("票已售完");
  29. return false;
  30. }
  31. count--;
  32. saleNum++;
  33. //模拟卖票的网络延时和业务处理时间
  34. try {
  35. Thread.sleep(300);
  36. } catch (InterruptedException e) {
  37. e.printStackTrace();
  38. }
  39. //买完票输谁买的,出售出几张,剩余几张
  40. System.out.println(Thread.currentThread().getName()
  41. +"--剩余---"+count+"张,已售出第"+saleNum+"张");
  42. // try {
  43. // //让线程进入等待队列
  44. // wait();
  45. // } catch (InterruptedException e) {
  46. // e.printStackTrace();
  47. // }
  48. return true;
  49. }
  50. }
  51. public static void main(String[] args) {
  52. SaleTicket st=new SaleTicket();
  53. Thread t1 = new Thread(st,"张嘉元");
  54. Thread t2 = new Thread(st,"吴宇恒");
  55. Thread t3 = new Thread(st,"黄牛党");
  56. t1.start();
  57. t2.start();
  58. t3.start();
  59. }

7、总结image.png

8、synchronized 和Lock的区别

※lock和synchronized的区别
synchronized是关键字;1.8优化后,锁升级(偏向锁—>轻量级锁/(CAS)自旋锁—>重量级锁),不可逆的
lock是java的类/接口;手动加锁手动释放,因为syn不可逆