码迷,mamicode.com
首页 > 编程语言 > 详细

7:多线程

时间:2015-10-26 18:27:09      阅读:385      评论:0      收藏:0      [点我收藏+]

标签:

基本概念
技术分享
进程:正在进行中的程序(直译).
线程:就是进程中一个负责程序执行的控制单元(执行路径) 
一个进程中可以多执行路径,称之为多线程,一个进程中至少要有一个线程。 
开启多个线程是为了同时运行多部分代码。 
每一个线程都有自己运行的内容。这个内容可以称为线程要执行的任务。 


多线程好处:解决了多部分同时运行的问题。
多线程的弊端:线程太多回到效率的降低。 
其实应用程序的执行都是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();
 |--在开发时,可以使用匿名内部类来完成局部的路径开辟。 






7:多线程

标签:

原文地址:http://www.cnblogs.com/liuyu0529/p/4911786.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!