7:多线程

基本概念

进程:正在进行中的程序(直译).

线程:就是进程中一个负责程序执行的控制单元(执行路径)

一个进程中可以多执行路径,称之为多线程,一个进程中至少要有一个线程。

开启多个线程是为了同时运行多部分代码。

每一个线程都有自己运行的内容。这个内容可以称为线程要执行的任务。

多线程好处:解决了多部分同时运行的问题。

多线程的弊端:线程太多回到效率的降低。

其实应用程序的执行都是cpu在做着快速的切换完成的。这个切换是随机的。

JVM启动时就启动了多个线程,至少有两个线程可以分析的出来。

1,执行main函数的线程,

该线程的任务代码都定义在main函数中。

2,负责垃圾回收的线程。


线程创建方法

创建线程方式一:继承Thread类。

步骤:

1,定义一个类继承Thread类。

2,覆盖Thread类中的run方法。

3,直接创建Thread的子类对象创建线程。

4,调用start方法开启线程并调用线程的任务run方法执行。

可以通过Thread的getName获取线程的名称 Thread-编号(从0开始)

主线程的名字就是main。

其中Thread.currentThrrad().getName,是获取当前对象的名字

创建线程的第二种方式:实现Runnable接口。

步骤:

1,定义类实现Runnable接口。

2,覆盖接口中的run方法,将线程的任务代码封装到run方法中。

3,通过Thread类创建线程对象,并将Runnable接口的子类对象作为Thread类的构造函数的参数进行传递。

为什么?因为线程的任务都封装在Runnable接口子类对象的run方法中。

所以要在线程对象创建时就必须明确要运行的任务。

4,调用线程对象的start方法开启线程。

实现Runnable接口的好处:

1,将线程的任务从线程的子类中分离出来,进行了单独的封装。

按照面向对象的思想将任务的封装成对象。

2,避免了java单继承的局限性。

所以,创建线程的第二种方式较为常用。

  1. class Demo implements Runnable// extends Fu //准备扩展Demo类的功能,让其中的内容可以作为线程的任务执行
  2. {
  3. public void run() {
  4. show();
  5. }
  6. public void show() {
  7. for (int x = 0; x < 20; x++) {
  8. System.out.println(Thread.currentThread().getName() + "....." + x);
  9. }
  10. }
  11. }
  12. class ThreadDemo {
  13. public static void main(String[] args) {
  14. Demo d = new Demo();
  15. Thread t1 = new Thread(d);
  16. Thread t2 = new Thread(d);
  17. t1.start();
  18. t2.start();
  19. }
  20. }


线程的生命周期

  • 指线程从创建到启动,直至运行结束
  • 可以通过调用Thread类的相关方法影响线程的运行状态


线程安全

线程安全问题产生的原因:

1,多个线程在操作共享的数据。

2,操作共享数据的线程代码有多条。

当一个线程在执行操作共享数据的多条代码过程中,其他线程参与了运算。

就会导致线程安全问题的产生。

解决思路;

就是将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,

其他线程时不可以参与运算的。

必须要当前线程把这些代码都执行完毕后,其他线程才可以参与运算。

在java中,用同步代码块就可以解决这个问题。

同步代码块的格式:

synchronized(对象)

{

需要被同步的代码 ;

}

同步的好处:解决了线程的安全问题。

同步的弊端:相对降低了效率,因为同步外的线程的都会判断同步锁。

同步的前提:同步中必须有多个线程并使用同一个锁。

同步函数的使用的锁是this;

同步函数和同步代码块的区别:

同步函数的锁是固定的this。

同步代码块的锁是任意的对象。

建议使用同步代码块。

eg:验证同步函数的锁

  1. class Ticket implements Runnable {
  2. private int num = 100;
  3. // Object obj = new Object();
  4. boolean flag = true;
  5. // 如果是真运行同步代码块,如果假运行同步函数?
  6. public void run() {
  7. // System.out.println("this:"+this);
  8. if (flag)
  9. while (true) {
  10. synchronized (this) {
  11. if (num > 0) {
  12. try {
  13. Thread.sleep(10);
  14. } catch (InterruptedException e) {
  15. }
  16. System.out.println(Thread.currentThread().getName()
  17. + ".....obj...." + num--);
  18. }
  19. }
  20. }
  21. else
  22. while (true)
  23. this.show();// 调用show方法
  24. }
  25. public synchronized void show() {// 将需要的放进来
  26. if (num > 0) {
  27. try {
  28. Thread.sleep(10);
  29. } catch (InterruptedException e) {
  30. }
  31. System.out.println(Thread.currentThread().getName()
  32. + ".....function...." + num--);
  33. }
  34. }
  35. }
  36. class SynFunctionLockDemo {
  37. public static void main(String[] args) {
  38. Ticket t = new Ticket();
  39. // System.out.println("t:"+t);
  40. Thread t1 = new Thread(t);
  41. Thread t2 = new Thread(t);
  42. t1.start();
  43. try {
  44. Thread.sleep(10);
  45. } catch (InterruptedException e) {
  46. }
  47. t.flag = false;// 标记下
  48. t2.start();
  49. }
  50. }

需求:储户,两个,每个都到银行存钱每次存100,,共存三次。

  1. class Bank {
  2. private int sum;
  3. // private Object obj = new Object();
  4. public synchronized void add(int num)// 同步函数
  5. {
  6. // synchronized(obj)
  7. // {
  8. sum = sum + num;
  9. // -->
  10. try {
  11. Thread.sleep(10);
  12. } catch (InterruptedException e) {
  13. }
  14. System.out.println("sum=" + sum);
  15. // }
  16. }
  17. }
  18. class Cus implements Runnable {
  19. private Bank b = new Bank();
  20. public void run() {
  21. for (int x = 0; x < 3; x++) {
  22. b.add(100);
  23. }
  24. }
  25. }
  26. class BankDemo {
  27. public static void main(String[] args) {
  28. Cus c = new Cus();
  29. Thread t1 = new Thread(c);
  30. Thread t2 = new Thread(c);
  31. t1.start();
  32. t2.start();
  33. }
  34. }

静态的同步函数使用的锁是:该函数所属字节码文件对象,它不能用this,静态方法中不能有this

可以用 getClass方法获取,也可以用当前  类名.class 表示。class文件只有一份

  1. class Ticket implements Runnable {
  2. private static int num = 100;
  3. // Object obj = new Object();
  4. boolean flag = true;
  5. public void run() {
  6. // System.out.println("this:"+this.getClass());
  7. if (flag)
  8. while (true) {
  9. synchronized (Ticket.class)// (this.getClass())都行
  10. {
  11. if (num > 0) {
  12. try {
  13. Thread.sleep(10);
  14. } catch (InterruptedException e) {
  15. }
  16. System.out.println(Thread.currentThread().getName()
  17. + ".....obj...." + num--);
  18. }
  19. }
  20. }
  21. else
  22. while (true)
  23. this.show();
  24. }
  25. public static synchronized void show() {
  26. if (num > 0) {
  27. try {
  28. Thread.sleep(10);
  29. } catch (InterruptedException e) {
  30. }
  31. System.out.println(Thread.currentThread().getName()
  32. + ".....function...." + num--);
  33. }
  34. }
  35. }
  36. class StaticSynFunctionLockDemo {
  37. public static void main(String[] args) {
  38. Ticket t = new Ticket();
  39. // Class clazz = t.getClass();
  40. // Class clazz = Ticket.class;
  41. // System.out.println("t:"+t.getClass());
  42. Thread t1 = new Thread(t);
  43. Thread t2 = new Thread(t);
  44. t1.start();
  45. try {
  46. Thread.sleep(10);
  47. } catch (InterruptedException e) {
  48. }
  49. t.flag = false;
  50. t2.start();
  51. }
  52. }

多线程下的单例

饿汉式(和一起一样)

  1. class Single {
  2. private static final Single s = new Single();
  3. private Single() {
  4. }
  5. public static Single getInstance() {
  6. return s;
  7. }
  8. }

懒汉式

加入同步为了解决多线程安全问题。

加入双重判断是为了解决效率问题。

  1. class Single {
  2. private static Single s = null;
  3. private Single() {
  4. }
  5. public static Single getInstance() {
  6. if (s == null)// 多加一步,0进来以后创建完对象。多加一次判断1进来就不是空了就不判断了
  7. {
  8. synchronized (Single.class) {
  9. if (s == null)
  10. // -->0 -->1,0判断完空,创建对象,1进来就来不判断了,直接创建新对象,所以加同步
  11. // 这里用同步函数不好,用代码块好,提高效率
  12. s = new Single();
  13. }
  14. }
  15. return s;
  16. }
  17. }

死锁:

情景一:同步的嵌套。

你不给我,我不给你筷子,你的同步有我的同步,我的同步有你同步,

情景二:全部等待

例一:

  1. class Ticket implements Runnable { // 这里有俩把锁this和obj
  2. private int num = 100;
  3. Object obj = new Object();
  4. boolean flag = true;
  5. public void run() {
  6. if (flag)
  7. while (true) {
  8. synchronized (obj) {
  9. show();// 拿着obj想进this
  10. }
  11. }
  12. else
  13. while (true)
  14. this.show();
  15. }
  16. public synchronized void show() {// 拿着this想进obj,互相拿着锁不放。和谐的时候是你进来我出去了
  17. synchronized (obj) // 同步函数加入同步代码块
  18. {
  19. if (num > 0) {
  20. try {
  21. Thread.sleep(10);
  22. } catch (InterruptedException e) {
  23. }
  24. System.out.println(Thread.currentThread().getName()
  25. + ".....sale...." + num--);
  26. }
  27. }
  28. }
  29. }
  30. class DeadLockDemo {
  31. public static void main(String[] args) {
  32. Ticket t = new Ticket();
  33. // System.out.println("t:"+t);
  34. Thread t1 = new Thread(t);
  35. Thread t2 = new Thread(t);
  36. t1.start();
  37. try {
  38. Thread.sleep(10);
  39. } catch (InterruptedException e) {
  40. }
  41. t.flag = false; // 切换
  42. t2.start();
  43. }
  44. }

例二:

  1. class Test implements Runnable {
  2. private boolean flag;
  3. Test(boolean flag) // 构造函数里赋值
  4. {
  5. this.flag = flag;
  6. }
  7. public void run() {
  8. if (flag) {
  9. while (true)
  10. synchronized (MyLock.locka) // a里有b
  11. {
  12. System.out.println(Thread.currentThread().getName()
  13. + "..if locka....");
  14. synchronized (MyLock.lockb) {
  15. System.out.println(Thread.currentThread().getName()
  16. + "..if lockb....");
  17. }
  18. }
  19. } else {
  20. while (true)
  21. synchronized (MyLock.lockb) { // b里有a
  22. {
  23. System.out.println(Thread.currentThread().getName()
  24. + "..else lockb....");
  25. synchronized (MyLock.locka) {
  26. System.out.println(Thread.currentThread().getName()
  27. + "..else locka....");
  28. }
  29. }
  30. }
  31. }
  32. }
  33. class MyLock {
  34. public static final Object locka = new Object();
  35. public static final Object lockb = new Object();
  36. }
  37. class DeadLockTest {
  38. public static void main(String[] args) {
  39. Test a = new Test(true);
  40. Test b = new Test(false);
  41. // 一般线程只有一个对象,因为多线程就是多个线程执行同一个任务,而这里FLAG的值只有俩种情况(真假)
  42. // 也是为了切换
  43. Thread t1 = new Thread(a);
  44. Thread t2 = new Thread(b);
  45. t1.start();
  46. t2.start();
  47. }
  48. }
  49. }

new object写在外边,写在里边创建了四个对象,有四把锁,用同步,必须保证多个线程使用同一个锁


线程间通讯

多个线程在处理同一资源,但是任务却不同。

版本1.0

  1. //资源
  2. class Resource {
  3. String name;
  4. String sex;
  5. }
  6. // 输入
  7. class Input implements Runnable {
  8. Resource r; // 参数传递
  9. // Object obj = new Object();
  10. Input(Resource r) {
  11. this.r = r;
  12. }
  13. public void run() {
  14. int x = 0;
  15. while (true) {
  16. synchronized (r)
  17. // 不能用this,obj,这里有俩个对象,得保证用一个唯一的对象,用参数的Class文件也可以,但是杀不用炮轰,所以用资源的参数就可以了
  18. {
  19. if (x == 0) {
  20. r.name = "mike";
  21. r.sex = "nan";
  22. } else {
  23. r.name = "丽丽";
  24. r.sex = "女女女女女女";
  25. }
  26. }
  27. x = (x + 1) % 2;
  28. }
  29. }
  30. }
  31. // 输出
  32. class Output implements Runnable {
  33. Resource r;
  34. // Object obj = new Object();
  35. Output(Resource r) {
  36. this.r = r;
  37. }
  38. public void run() {
  39. while (true) {
  40. synchronized (r) {
  41. System.out.println(r.name + "....." + r.sex);
  42. }
  43. }
  44. }
  45. }
  46. class ResourceDemo {
  47. public static void main(String[] args) {
  48. // 创建资源。
  49. Resource r = new Resource();
  50. // 创建任务。
  51. Input in = new Input(r);
  52. Output out = new Output(r);
  53. // 创建线程,执行路径。
  54. Thread t1 = new Thread(in);
  55. Thread t2 = new Thread(out);
  56. // 开启线程
  57. t1.start();
  58. t2.start();
  59. }
  60. }

这个代码会出现一大片,我们希望的是输入一次输出一次,用唤醒等待

等待/唤醒机制。

涉及的方法:

1,wait(): 让线程处于冻结状态,被wait的线程会被存储到线程池中。

2,notify():唤醒线程池中一个线程(任意).

3,notifyAll():唤醒线程池中的所有线程。

这些方法都必须定义在同步中。

俩帮小朋友玩游戏,你wait,另一帮玩的不能叫醒你,就像需要同一把锁。

因为这些方法是用于操作线程状态的方法。

必须要明确到底操作的是哪个锁上的线程。

为什么操作线程的方法wait notify notifyAll定义在了Object类中?

因为这些方法是监视器的方法。监视器其实就是锁。

锁可以是任意的对象,任意的对象调用的方式一定定义在Object类中。

版本2.0

  1. //资源
  2. class Resource {
  3. String name;
  4. String sex;
  5. boolean flag = false;
  6. }
  7. // 输入
  8. class Input implements Runnable {
  9. Resource r;
  10. // Object obj = new Object();
  11. Input(Resource r) {
  12. this.r = r;
  13. }
  14. public void run() {
  15. int x = 0;
  16. while (true) {
  17. synchronized (r) {
  18. if (r.flag)
  19. try {
  20. r.wait();
  21. } catch (InterruptedException e) {
  22. }
  23. // r.wait俩帮小朋友玩游戏,你wait,另一帮不能叫醒你,一把锁
  24. if (x == 0) {
  25. r.name = "mike";
  26. r.sex = "nan";
  27. } else {
  28. r.name = "丽丽";
  29. r.sex = "女女女女女女";
  30. }
  31. r.flag = true;
  32. r.notify();
  33. }
  34. x = (x + 1) % 2;
  35. }
  36. }
  37. }
  38. // 输出
  39. class Output implements Runnable {
  40. Resource r;
  41. // Object obj = new Object();
  42. Output(Resource r) {
  43. this.r = r;
  44. }
  45. public void run() {
  46. while (true) {
  47. synchronized (r) {
  48. if (!r.flag)
  49. try {
  50. r.wait();
  51. } catch (InterruptedException e) {
  52. }
  53. System.out.println(r.name + "....." + r.sex);
  54. r.flag = false;
  55. r.notify();
  56. }
  57. }
  58. }
  59. }
  60. class ResourceDemo2 {
  61. public static void main(String[] args) {
  62. // 创建资源。
  63. Resource r = new Resource();
  64. // 创建任务。
  65. Input in = new Input(r);
  66. Output out = new Output(r);
  67. // 创建线程,执行路径
  68. Thread t1 = new Thread(in);
  69. Thread t2 = new Thread(out);
  70. // 开启线程
  71. t1.start();
  72. t2.start();
  73. }
  74. }

版本3.0最终,修改优化后的:

  1. class Resource { // 将资源私有化,提高安全性
  2. private String name;
  3. private String sex;
  4. private boolean flag = false;
  5. public synchronized void set(String name, String sex) { // 同步写在这,需要同步就是这个
  6. if (flag)
  7. try {
  8. this.wait();
  9. } catch (InterruptedException e) {
  10. } // wait锁上的方法写在同步里
  11. this.name = name;
  12. this.sex = sex;
  13. flag = true;
  14. this.notify();
  15. }
  16. public synchronized void out() { // 同步写在这,需要同步就是这个
  17. if (!flag)
  18. try {
  19. this.wait();
  20. } catch (InterruptedException e) {
  21. }
  22. System.out.println(name + "...+...." + sex);
  23. flag = false;
  24. notify();
  25. }
  26. }
  27. // 输入
  28. class Input implements Runnable {
  29. Resource r;
  30. // Object obj = new Object();
  31. Input(Resource r) {
  32. this.r = r;
  33. }
  34. public void run() {
  35. int x = 0;
  36. while (true) {
  37. if (x == 0) {
  38. r.set("mike", "nan");
  39. } else {
  40. r.set("丽丽", "女女女女女女");
  41. }
  42. x = (x + 1) % 2;
  43. }
  44. }
  45. }
  46. // 输出
  47. class Output implements Runnable {
  48. Resource r;
  49. // Object obj = new Object();
  50. Output(Resource r) {
  51. this.r = r;
  52. }
  53. public void run() {
  54. while (true) {
  55. r.out();
  56. }
  57. }
  58. }
  59. class ResourceDemo3 {
  60. public static void main(String[] args) {
  61. // 创建资源。
  62. Resource r = new Resource();
  63. // 创建任务。
  64. Input in = new Input(r);
  65. Output out = new Output(r);
  66. // 创建线程,执行路径
  67. Thread t1 = new Thread(in);
  68. Thread t2 = new Thread(out);
  69. // 开启线程
  70. t1.start();
  71. t2.start();
  72. }
  73. }

生产者,消费者。

多生产者,多消费者的问题。

多生产者,多消费者的时候

if判断标记,只有一次,会导致不该运行的线程运行了。出现了数据错误的情况。

出现生产一次消费多次,或者生产多次消费一次的现象,因为只判断一次,从wait那醒的,不再判断了。

可是还会出现全部等待的情况,即死锁的另外一种情况

while判断标记,解决了线程获取执行权后,是否要运行!

notify:只能唤醒一个线程,如果本方唤醒了本方,没有意义。而且while判断标记+notify会导致死锁。

notifyAll解决了本方线程一定会唤醒对方线程的问题。

  1. class Resource {
  2. private String name;
  3. private int count = 1;
  4. private boolean flag = false;
  5. public synchronized void set(String name)//
  6. {
  7. while (flag)
  8. try {
  9. this.wait();
  10. } catch (InterruptedException e) {
  11. }// t1 t0 if的话 从这醒的,不再判断了
  12. this.name = name + count;// 烤鸭1 烤鸭2 烤鸭3
  13. count++;// 2 3 4
  14. System.out.println(Thread.currentThread().getName() + "...生产者..."
  15. + this.name);// 生产烤鸭1 生产烤鸭2 生产烤鸭3
  16. flag = true;
  17. notifyAll();
  18. }
  19. public synchronized void out()// t3
  20. {
  21. while (!flag)
  22. try {
  23. this.wait();
  24. } catch (InterruptedException e) {
  25. } // t2 t3
  26. System.out.println(Thread.currentThread().getName() + "...消费者........"
  27. + this.name);// 消费烤鸭1
  28. flag = false;
  29. notifyAll();
  30. }
  31. }
  32. class Producer implements Runnable {
  33. private Resource r;
  34. Producer(Resource r) {
  35. this.r = r;
  36. }
  37. public void run() {
  38. while (true) {
  39. r.set("烤鸭");
  40. }
  41. }
  42. }
  43. class Consumer implements Runnable {
  44. private Resource r;
  45. Consumer(Resource r) {
  46. this.r = r;
  47. }
  48. public void run() {
  49. while (true) {
  50. r.out();
  51. }
  52. }
  53. }
  54. class ProducerConsumerDemo {
  55. public static void main(String[] args) {
  56. Resource r = new Resource();
  57. Producer pro = new Producer(r);
  58. Consumer con = new Consumer(r);
  59. Thread t0 = new Thread(pro);
  60. Thread t1 = new Thread(pro);
  61. Thread t2 = new Thread(con);
  62. Thread t3 = new Thread(con);
  63. t0.start();
  64. t1.start();
  65. t2.start();
  66. t3.start();
  67. }
  68. }

多生产多消费

全唤醒都判断效率不高, 
能不能只唤醒对方呢?

jdk1.5以后将同步和锁封装成了对象。

并将操作锁的隐式方式定义到了该对象中,

将隐式动作变成了显示动作。

Lock接口: 出现替代了同步代码块或者同步函数。将同步的隐式锁操作变成现实锁操作。

同时更为灵活。可以一个锁上加上多组监视器。

lock():获取锁。

unlock():释放锁,通常需要定义finally代码块中。

Condition接口:出现替代了Object中的wait notify notifyAll方法。

将这些监视器方法单独进行了封装,变成Condition监视器对象。

可以任意锁进行组合。

await();

signal();

signalAll();

  1. import java.util.concurrent.locks.*; //如果不导包lock就写全称
  2. class Resource {
  3. private String name;
  4. private int count = 1;
  5. private boolean flag = false;
  6. // 创建一个锁对象。
  7. Lock lock = new ReentrantLock(); // 是lock接口的子类,自定义锁
  8. // lock 这个锁可以挂多个锁,通过已有的锁获取该锁上的监视器对象
  9. // Condition con = lock.newCondition(); //lock.newCondition(),lock的方法
  10. // 通过已有的锁获取两组监视器,一组监视生产者,一组监视消费者。
  11. Condition producer_con = lock.newCondition();
  12. Condition consumer_con = lock.newCondition();
  13. public void set(String name)// t0 t1
  14. {
  15. lock.lock();
  16. try {
  17. while (flag)
  18. // try{lock.wait();}catch(InterruptedException e){}// t1 t0
  19. try {
  20. producer_con.await();
  21. } catch (InterruptedException e) {
  22. }// t1 t0
  23. this.name = name + count;// 烤鸭1 烤鸭2 烤鸭3
  24. count++;// 2 3 4
  25. System.out.println(Thread.currentThread().getName()
  26. + "...生产者5.0..." + this.name);// 生产烤鸭1 生产烤鸭2 生产烤鸭3
  27. flag = true;
  28. // notifyAll();
  29. // con.signalAll();
  30. consumer_con.signal();
  31. } // 不准备处理异常,所以不需要catch
  32. finally {
  33. lock.unlock();
  34. }
  35. }
  36. public void out()// t2 t3
  37. {
  38. lock.lock();
  39. try {
  40. while (!flag)
  41. // try{this.wait();}catch(InterruptedException e){} //t2 t3
  42. try {
  43. cousumer_con.await();
  44. } catch (InterruptedException e) {
  45. } // t2 t3
  46. System.out.println(Thread.currentThread().getName()
  47. + "...消费者.5.0......." + this.name);// 消费烤鸭1
  48. flag = false;
  49. // notifyAll();
  50. // con.signalAll();
  51. producer_con.signal();
  52. } finally {
  53. lock.unlock();
  54. }
  55. }
  56. }
  57. class Producer implements Runnable {
  58. private Resource r;
  59. Producer(Resource r) {
  60. this.r = r;
  61. }
  62. public void run() {
  63. while (true) {
  64. r.set("烤鸭");
  65. }
  66. }
  67. }
  68. class Consumer implements Runnable {
  69. private Resource r;
  70. Consumer(Resource r) {
  71. this.r = r;
  72. }
  73. public void run() {
  74. while (true) {
  75. r.out();
  76. }
  77. }
  78. }
  79. class ProducerConsumerDemo2 {
  80. public static void main(String[] args) {
  81. Resource r = new Resource();
  82. Producer pro = new Producer(r);
  83. Consumer con = new Consumer(r);
  84. Thread t0 = new Thread(pro);
  85. Thread t1 = new Thread(pro);
  86. Thread t2 = new Thread(con);
  87. Thread t3 = new Thread(con);
  88. t0.start();
  89. t1.start();
  90. t2.start();
  91. t3.start();
  92. }
  93. }

wait 和 sleep 区别?

1,wait可以指定时间也可以不指定。

sleep必须指定时间。

2,在同步中时,对cpu的执行权和锁的处理不同。 他们都是冻结状态:释放执行权和资格

wait:释放执行权,释放锁。释放锁别的才能进来

sleep:释放执行权,不释放锁。因为他不需要别人叫

  1. class Demo {
  2. void show() {
  3. synchronized (this)//
  4. {
  5. wait();// t0 t1 t2全活了
  6. }
  7. }
  8. void method() {
  9. synchronized (this)// t4
  10. {
  11. // wait();
  12. notifyAll();
  13. }// t4
  14. }
  15. }

会出现全活状态,但是谁拿锁谁执行,不懂,参见多线程32

停止线程俩种方法:

1,stop方法。
强制性的,会出现危险,就像人跑的跑的没了

2,run方法结束。 很常用:

怎么控制线程的任务结束呢?

任务中都会有循环结构,只要控制住循环就可以结束任务。

控制循环通常就用定义标记来完成。

可是也有停不下来的时候,如同步时第一次读完标记,第二次就不读取标记了,结果全等待。

线程处于冻结状态(全部等待),不能用唤醒,因为notify必须同一个锁中。如何结束呢?

可以使用interrupt()方法将线程从冻结状态强制恢复到运行状态中来,让线程具备cpu的执行资格。

当强制动作会发生了InterruptedException,记得要处理

  1. class StopThread implements Runnable {
  2. private boolean flag = true; // ture就转
  3. public synchronized void run() {
  4. while (flag)
  5. // 为什么经常在run方法写循环,因为短了也不值得开启多线程。不写while(ture)
  6. {
  7. try {
  8. wait();// t0 t1
  9. } catch (InterruptedException e) {
  10. System.out.println(Thread.currentThread().getName() + "....."
  11. + e);
  12. flag = false; // 强制把你们恢复回来,再读到标记就会结束掉。wait是等待不是结束
  13. }
  14. System.out.println(Thread.currentThread().getName() + "......++++");
  15. }
  16. }
  17. public void setFlag() {
  18. flag = false; // 把标记置为假
  19. }
  20. }
  21. class StopThreadDemo {
  22. public static void main(String[] args) {
  23. StopThread st = new StopThread();
  24. Thread t1 = new Thread(st);
  25. Thread t2 = new Thread(st);
  26. t1.start();
  27. t2.setDaemon(true); // setDameon是守护线程,可以理解为后台线程,你停我也停。前台必须手动结束
  28. t2.start();
  29. // 下边是主线程
  30. int num = 1;
  31. for (;;) // 无限循环
  32. {
  33. if (++num == 50) {
  34. // st.setFlag(); 把标记置为假,结束while循环
  35. t1.interrupt();
  36. // t2.interrupt(); //验证守护线程
  37. break; // 结束for循环
  38. }
  39. System.out.println("main...." + num);
  40. }
  41. System.out.println("over");
  42. }
  43. }

join等方法

  1. class Demo implements Runnable {
  2. public void run() {
  3. for (int x = 0; x < 50; x++) {
  4. System.out.println(Thread.currentThread().toString() + "....." + x);
  5. // tostring输出字符串,里面有名字、优先级(默认是5,常量是大写)
  6. Thread.yield(); // 会成对的出现,你一下我一下
  7. }
  8. }
  9. }
  10. class JoinDemo {
  11. public static void main(String[] args) throws Exception {
  12. Demo d = new Demo();
  13. Thread t1 = new Thread(d);
  14. Thread t2 = new Thread(d);
  15. t1.start();
  16. t2.start();
  17. // t2.setPriority(Thread.MAX_PRIORITY);
  18. // t1.join();//t1线程要申请加入进来,运行(主线程释放执行权和资格)。t1结束主线程才能执行,t2.join也一样,临时加入一个线程运算时可以使用join方法
  19. for (int x = 0; x < 50; x++) {
  20. // System.out.println(Thread.currentThread()+"....."+x);
  21. }
  22. }
  23. }


面试题

面试题1

/*class Test implements Runnable

{

public void run(Thread t)

{}

}*/

//如果错误 错误发生在哪一行?错误在第一行,实现接口不重写方法,还是抽象类,应该被abstract修饰

面试题2:

三种开启线程匿名内部类的方法

  1. class ThreadTest {
  2. public static void main(String[] args) {
  3. new Thread(new Runnable() {
  4. public void run() {
  5. System.out.println("runnable run");
  6. }
  7. }) { // 有复写了父类的run方法,输出的是子类
  8. public void run() {
  9. System.out.println("subThread run"); // 输出的是子类
  10. }
  11. }.start();
  12. // 随时开辟一个线程,匿名内部类,这里有三个
  13. new Thread() {
  14. public void run() {
  15. for (int x = 0; x < 50; x++) {
  16. System.out.println(Thread.currentThread().getName()
  17. + "....x=" + x);
  18. }
  19. }
  20. }.start();
  21. for (int x = 0; x < 50; x++) {
  22. System.out.println(Thread.currentThread().getName() + "....y=" + x);
  23. }
  24. Runnable r = new Runnable() {
  25. public void run() {
  26. for (int x = 0; x < 50; x++) {
  27. System.out.println(Thread.currentThread().getName()
  28. + "....z=" + x);
  29. }
  30. }
  31. };
  32. new Thread(r).start();
  33. }
  34. }

总结

1,进程和线程的概念。

|--进程:

|--线程:

2,jvm中的多线程体现。

|--主线程,垃圾回收线程,自定义线程。以及他们运行的代码的位置。

3,什么时候使用多线程,多线程的好处是什么?创建线程的目的?

|--当需要多部分代码同时执行的时候,可以使用。

4,创建线程的两种方式。★★★★★

|--继承Thread

|--步骤

|--实现Runnable

|--步骤

|--两种方式的区别?

5,线程的5种状态。

对于执行资格和执行权在状态中的具体特点。

|--被创建:

|--运行:

|--冻结:

|--临时阻塞:

|--消亡:

6,线程的安全问题。★★★★★

|--安全问题的原因:

|--解决的思想:

|--解决的体现:synchronized

|--同步的前提:但是加上同步还出现安全问题,就需要用前提来思考。

|--同步的两种表现方法和区别:

|--同步的好处和弊端:

|--单例的懒汉式。

|--死锁。

7,线程间的通信。等待/唤醒机制。

|--概念:多个线程,不同任务,处理同一资源。

|--等待唤醒机制。使用了锁上的 wait notify notifyAll.  ★★★★★

|--生产者/消费者的问题。并多生产和多消费的问题。  while判断标记。用notifyAll唤醒对方。 ★★★★★

|--JDK1.5以后出现了更好的方案,★★★

Lock接口替代了synchronized

Condition接口替代了Object中的监视方法,并将监视器方法封装成了Condition

和以前不同的是,以前一个锁上只能有一组监视器方法。现在,一个Lock锁上可以多组监视器方法对象。

可以实现一组负责生产者,一组负责消费者。

|--wait和sleep的区别。★★★★★

8,停止线程的方式。

|--原理:

|--表现:--中断。

9,线程常见的一些方法。

|--setDaemon()

|--join();

|--优先级

|--yield();

|--在开发时,可以使用匿名内部类来完成局部的路径开辟。

来自为知笔记(Wiz)

时间: 2024-08-27 06:12:35

7:多线程的相关文章

Java多线程学习(吐血超详细总结)

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka 目录(?)[-] 一扩展javalangThread类 二实现javalangRunnable接口 三Thread和Runnable的区别 四线程状态转换 五线程调度 六常用函数说明 使用方式 为什么要用join方法 七常见线程名词解释 八线程同步 九线程数据传递 本文主要讲了java中多线程的使用方法.线程同步.线程数据传递.线程状态及相应的一些线程函数用法.概述等. 首先讲一下进程和线程

Spring多线程

Spring是通过TaskExecutor任务执行器来实现多线程和并发编程的.使用ThreadPoolTaskExecutor可实现一个基于线程池的TaskExecutor.而实际开发中任务一般是非阻碍的,即异步的,所以我们要在配置类中通过@EnableAsync开启对异步的支持,并通过在实际执行的Bean的方法中使用@Async注解来声明其是一个异步任务. 实例代码: (1)配置类 package com.lwh.highlight_spring4.ch3.taskexecutor; /**

python进阶学习(一)--多线程编程

1. 多线程 概念:简单地说操作系统可以同时执行多个不用程序.例如:一边用浏览器上网,一边在听音乐,一边在用笔记软件记笔记. 并发:指的是任务数多余cpu核数,通过操作系统的各种任务调度算法,实现用多个任务"一起"执行(实际上总有一些任务不在执行,因为切换任务的熟度相当快,看上去一起执行而已) 并行:指的是任务数小于等于CPU核数,即任务真的是一起执行的. 2. 线程 概念:线程是进程的一个实体,是CPU调度和分派的基本单位. threading--单线程执行: 1 import ti

多线程的实现及其安全问题

一.进程和线程概述 1.进程:进程是一个具有独立功能的程序关于某个数据集合的一次运行活动,简单来说开启一个程序就开启了一个进程: 如果开启多个进程,它们之间是由于CPU的时间片在相互的切换: 2.线程:开启一个进程的一个任务,对于多线程:每一个线程都在争夺CPU的执行权(CPU的执行权具有随机性): 如果一个程序的执行路径有多条,那么该线程是多线程;反之,就单线程线程:线程是依赖于进程存在的! 3.Jvm是多线程 -- 至少开启了两条线程 main方法 主线程 gc() 垃圾回收线程 二.多线程

多线程和多进程的区别与联系

1.单进程单线程:一个人在一个桌子上吃菜.2.单进程多线程:多个人在同一个桌子上一起吃菜.3.多进程单线程:多个人每个人在自己的桌子上吃菜. 多线程的问题是多个人同时吃一道菜的时候容易发生争抢,例如两个人同时夹一个菜,一个人刚伸出筷子,结果伸到的时候已经被夹走菜了...此时就必须等一个人夹一口之后,在还给另外一个人夹菜,也就是说资源共享就会发生冲突争抢. 1.对于 Windows 系统来说,[开桌子]的开销很大,因此 Windows 鼓励大家在一个桌子上吃菜.因此 Windows 多线程学习重点

Python有了asyncio和aiohttp在爬虫这类型IO任务中多线程/多进程还有存在的必要吗?

最近正在学习Python中的异步编程,看了一些博客后做了一些小测验:对比asyncio+aiohttp的爬虫和asyncio+aiohttp+concurrent.futures(线程池/进程池)在效率中的差异,注释:在爬虫中我几乎没有使用任何计算性任务,为了探测异步的性能,全部都只是做了网络IO请求,就是说aiohttp把网页get完就程序就done了. 结果发现前者的效率比后者还要高.我询问了另外一位博主,(提供代码的博主没回我信息),他说使用concurrent.futures的话因为我全

多线程(一)

这边来谈谈java中,我对对多线程的理解 在了解多线程前,先说说进程. 进程就是正在运行的应用程序.  当你打开任务管理器的时候,你就会发现很多的进程. 而我们要说的线程,就是依赖于进程而存在的,一个进程可以开启多个线程. Thread类 说到线程,就必须来说说Thread类. Thread类是说有线程的父类.具体请参见api 线程的创建以及执行(图解如下) 继承Thread类,或者实现rennable接口. 当继承了父类后,需要重写父类的run方法,这个run方法里面就写你要执行的代码,当这个

多线程下的单例-double check

话不多说直接上代码: public sealed class Singleton { private static Singleton _instance = null; // Creates an syn object. private static readonly object SynObject = new object(); Singleton() { } public static Singleton Instance { get { // Double-Checked Lockin

笔记:多线程

多线程程序在较低的层次上扩展了多任务的概念:一个程序同时执行多个任务,通常每个任务称为一个线程(thread),他是线程控制的简称,可以同时运行一个以上线程的程序称为多线程程序(multithreaded):多线程和多进程有哪些区别呢,本质的区别在于每个进程拥有自己的一整套变量,而线程则是共享数据,Java中启动一个线程的代码如下: // 线程任务的具体实现接口 ????public interface Runnable { public abstract void run(); ????} /

多线程

1.线程的概念? 多线程,就类似与操作系统中的多进程.简单的讲,就是可 以同时并发执行多个任务,处理多件事情.这与我们经常所 谓的边唱边跳,边说边做事一个道理.? 线程是一个轻量级的进程,一个进程中可以分为多个线程. 比起进程,线程所耗费的系统资源更少,切换更加容易 /* * 进程是操作系统中的一个任务,一个程序启动运行,就会创建 * 一个(或多个)进程. * 线程是轻量级的进程.进程会有自己独立的内存空间与资源.一个进程 * 下会存在一个(或多个)线程.线程为进程的执行单元.线程本身不含有 *