一、多线程

1、概述

1.1 理解线程和进程

  • 进程时一个应用程序(软件)

  • 线程是一个进程的执行过程/执行场景

  • 一个进程可以启动多个线程

1.2 java中实现多线程的两种方式

  1. 创建一个类,直接继承**java.lang.Thread** 重写**run()**方法
  • 在run方法中的代码运行在分支线程中
  1. 创建一个类,实现**Runnable**接口(常用)

方法

  • **start ()**//启动线程

  • **setName()** //修改线程名字

  • **getName()** //得到线程名字

  • 默认线程名 Thread-0 /1/2

**Thread.currentThread()** 静态方法

//得到当前线程在哪里出现获取得就是拿的线程

  1. Thread t1 = Thread.currentThread();

**Thread.sleep**``(``毫秒``) 静态方法

//让线程睡眠 出现在哪里就是让那个线程睡眠

  1. **interrupt()**

//唤醒睡眠的线程

原理就是直接进去catch语句

合理结束线程

打一个布尔标记

实现线程的第三种方式 实现Callable接口

这种方式可以获取线程的返回值

1.3 代码-java实现多线程方式1 继承 Thread类

  1. public class TreadTest001 {
  2. public static void main(String[] args) {
  3. A a = new A();
  4. a.start(); // 启动线程
  5. for (int i = 0; i < 1000; i++){
  6. System.out.println("主线程"+i);
  7. }
  8. }
  9. }
  10. class A extends Thread{
  11. @Override
  12. public void run() {
  13. for (int i = 0; i < 1000; i++){
  14. System.out.println("分支线程"+i);
  15. }
  16. }
  17. }

1.4 代码—-java实现多线程方式2 实现 Runnable 接口

  1. public class ThreadTest01 {
  2. public static void main(String[] args) {
  3. Thread s = new Thread(new MyThread02());
  4. s.start(); //启动线程
  5. for (int i = 0; i < 100; i++){
  6. System.out.println("主线程"+i);
  7. }
  8. }
  9. }
  10. class MyThread02 implements Runnable{
  11. @Override
  12. public void run() {
  13. for (int i = 0; i < 100; i++){
  14. System.out.println("分支线程"+i);
  15. }
  16. }
  17. }

1.5线程的五种状态

多线程和JUC - 图1

二、多线程并发/守护线程

1、满足条件

  1. 多线程并发

  2. 有共享数据

  3. 共享数据有修改的行为

2、解决线程安全问题

  1. 线程排队执行(不能并发)

  2. 尽量使用局部变量代替实例变量/静态变量

  3. 如果必须是实例变量,那么可以考虑多new几个对象

  4. 以上都不行采用synchronized

这种机制被称为”线程同步机制“

3、synchronized

线程同步机制语法

  1. synchronized(共享对象) {
  2. //同步代码块 (和谁同步,填谁和谁的同步对象)
  3. }

synchronized出现在实例方法上,锁的是this(不灵活)

  1. public synchronized void doSome(){}

在静态方法上使用synchronized

表示找类锁,类锁永远只有一把

对象锁:一个对象一把锁,一百个对象一百把锁

类锁:100个对象,1把锁

sybchronized 在开发中尽量不要嵌套使用,容易死锁

局部变量不存在线程安全问题

4、守护线程

后台线程 例如:垃圾回收线程

特点:死循环,用户线程结束守护线程自动结束

语法

**setDaemon(true);** // 变成守护线程

**t.setDaemon(true);** //t线程变成守护线程

即使t线程里面是死循环,当主线程结束,守护线程也会结束

三、生产者和消费者

1、概述

  • wait()notify()

  • 不是线程对象的方法

  • 任何一个java对象都有的方法(Object自带)

  • wait()notify()必须建立在synchroniezd基础上

2、wait()

  • Object o = new Object();

  • o.wait();

  • 表示让正在o对象上活动的线程进入等待状态(无期限)

  • 直到调用o.notify()方法

  • 会释放锁

3、notify()

  • o.notify();

  • 唤醒正在等待的线程

  • 不会释放锁

4、死锁

  1. //死锁
  2. public class DeadThread {
  3. public static void main(String[] args) {
  4. Object a = new Object();
  5. Object b = new Object();
  6. MyThread1 one = new MyThread1(a,b); //线程对象one
  7. MyThread2 two = new MyThread2(a,b); //线程对象two
  8. one.start(); //启动线程one
  9. two.start(); //启动线程two
  10. }
  11. }
  12. class MyThread1 extends Thread{
  13. Object one;
  14. Object two;
  15. public MyThread1(Object one, Object two) {
  16. this.one = one;
  17. this.two = two;
  18. }
  19. @Override
  20. public void run() {
  21. synchronized(one){
  22. try {
  23. Thread.sleep(2000); //睡眠2秒
  24. } catch (InterruptedException e) {
  25. e.printStackTrace();
  26. }
  27. synchronized (two){
  28. }
  29. }
  30. }
  31. }
  32. class MyThread2 extends Thread{
  33. Object one;
  34. Object two;
  35. public MyThread2(Object one, Object two) {
  36. this.one = one;
  37. this.two = two;
  38. }
  39. @Override
  40. public void run() {
  41. synchronized(two){
  42. try {
  43. Thread.sleep(2000); //睡眠两秒
  44. } catch (InterruptedException e) {
  45. e.printStackTrace();
  46. }
  47. synchronized (one){
  48. }
  49. }
  50. }
  51. }

5、synchronized有三种写法:

第一种:同步代码块 灵活

  1. synchronized(线程共享对象){
  2. 同步代码块;
  3. }

第二种:在实例方法上使用synchronized

表示共享对象一定是this

并且同步代码块是整个方法体

第三种:在静态方法上使用synchronized

表示找类锁。

类锁永远只有1把。

就算创建了100个对象,那类锁也只有一把

对象锁:1个对象1把锁,100个对象100把锁。

类锁:100个对象,也可能只是1把类锁。