分享

多线程的运行特点

 集微笔记 2013-10-14

  • 尽管多线程启动时是有顺序的(通常是for循环),但真正运行起来后,其实没有完全的先后顺序
起10个线程
        Test test = new Test();
    for (int i = 0; i < 10; i++) {
      Thread thread = new Thread(test, "thread-" + i);
      thread.start();
    }
看执行:
thread-1:a:10
thread-1:b:3
thread-4:a:11
thread-4:b:3
thread-6:a:12
thread-6:b:7 

  • 基础的多线程————基于语句,无序竞争
    public void doWrite() {
        log.info("start to a++");
        a++;
        log.info("a++ finihed");
       
        log.info("start to b++");
        b++;
        log.info("b++ finished");

    }

    public void print() {
        System.out.println("" + Thread.currentThread().getName() + ":a:" + a);
        System.out.println("" + Thread.currentThread().getName() + ":b:" + b);
    }

    public void run() {
        for (int i = 0; i < 10; i++) {
            doWrite();
            print();

        }
执行结果:
发现各线程的方法很难完整从到尾一气呵成的执行,证明多线程是基于语句的而不是基于方法的
[INFO ] 2010-05-21 17:10:05,312 thread-0 start to a++
[INFO ] 2010-05-21 17:10:05,312 thread-9 start to a++
[INFO ] 2010-05-21 17:10:05,312 thread-9 a++ finihed
[INFO ] 2010-05-21 17:10:05,312 thread-9 start to b++
[INFO ] 2010-05-21 17:10:05,312 thread-9 b++ finished
thread-9:a:2
thread-9:b:1
thread-5:b:3
[INFO ] 2010-05-21 17:10:05,328 thread-3 start to a++    线程3的a++被线程1打断
[INFO ] 2010-05-21 17:10:05,312 thread-1 start to a++
[INFO ] 2010-05-21 17:10:05,328 thread-1 a++ finihed
[INFO ] 2010-05-21 17:10:05,328 thread-1 start to b++
[INFO ] 2010-05-21 17:10:05,328 thread-1 b++ finished
thread-1:a:8
thread-1:b:6
[INFO ] 2010-05-21 17:10:05,328 thread-3 a++ finihed      直到此句线程3的a++ 才执行完
[INFO ] 2010-05-21 17:10:05,328 thread-3 start to b++
[INFO ] 2010-05-21 17:10:05,328 thread-3 b++ finished 


  • 加了sleep/intercept的多线程: 各线程竞争更合理更有序
    public void doWrite() {
        log.info("start to a++");
        a++;
        log.info("a++ finihed");
        try {
            sleep((int) (Math.random() * 100));
        } catch (InterruptedException e) {
        }

        log.info("start to b++");
        b++;
        log.info("b++ finished");
        try {
            sleep((int) (Math.random() * 100));
        } catch (InterruptedException e) {
        }
    }
各线程的语句执行情况大为改观
尽管各线程仍存在竞争,各线程方法仍很难完整执行
但加了sleep/interrupted后,等于增加了调度功能,各线程竞争更合理,更有序

[INFO ] 2010-05-21 17:20:00,593 thread-6 start to a++
[INFO ] 2010-05-21 17:20:00,593 thread-6 a++ finihed
[INFO ] 2010-05-21 17:20:00,593 thread-1 start to a++
[INFO ] 2010-05-21 17:20:00,609 thread-1 a++ finihed
[INFO ] 2010-05-21 17:20:00,593 thread-4 start to a++
[INFO ] 2010-05-21 17:20:00,593 thread-2 start to a++
[INFO ] 2010-05-21 17:20:00,609 thread-2 a++ finihed
[INFO ] 2010-05-21 17:20:00,593 thread-0 start to a++
[INFO ] 2010-05-21 17:20:00,609 thread-3 start to a++
[INFO ] 2010-05-21 17:20:00,609 thread-3 a++ finihed
[INFO ] 2010-05-21 17:20:00,609 thread-4 a++ finihed
[INFO ] 2010-05-21 17:20:00,609 thread-8 start to a++
[INFO ] 2010-05-21 17:20:00,609 thread-5 start to a++
[INFO ] 2010-05-21 17:20:00,609 thread-5 a++ finihed
[INFO ] 2010-05-21 17:20:00,609 thread-0 a++ finihed
[INFO ] 2010-05-21 17:20:00,609 thread-7 start to a++
[INFO ] 2010-05-21 17:20:00,609 thread-7 a++ finihed
[INFO ] 2010-05-21 17:20:00,609 thread-8 a++ finihed
[INFO ] 2010-05-21 17:20:00,609 thread-9 start to a++
[INFO ] 2010-05-21 17:20:00,609 thread-9 a++ finihed
[INFO ] 2010-05-21 17:20:00,609 thread-0 start to b++
[INFO ] 2010-05-21 17:20:00,609 thread-0 b++ finished
[INFO ] 2010-05-21 17:20:00,609 thread-8 start to b++
[INFO ] 2010-05-21 17:20:00,609 thread-8 b++ finished
[INFO ] 2010-05-21 17:20:00,609 thread-2 start to b++
[INFO ] 2010-05-21 17:20:00,609 thread-2 b++ finished
[INFO ] 2010-05-21 17:20:00,625 thread-3 start to b++
[INFO ] 2010-05-21 17:20:00,625 thread-3 b++ finished
[INFO ] 2010-05-21 17:20:00,640 thread-5 start to b++
[INFO ] 2010-05-21 17:20:00,640 thread-5 b++ finished
[INFO ] 2010-05-21 17:20:00,640 thread-1 start to b++
[INFO ] 2010-05-21 17:20:00,640 thread-1 b++ finished
thread-3:a:10
thread-3:b:6
[INFO ] 2010-05-21 17:20:00,656 thread-3 start to a++
[INFO ] 2010-05-21 17:20:00,656 thread-3 a++ finihed
thread-1:a:11
thread-1:b:6
[INFO ] 2010-05-21 17:20:00,656 thread-1 start to a++
[INFO ] 2010-05-21 17:20:00,656 thread-1 a++ finihed
thread-8:a:12
thread-8:b:6
[INFO ] 2010-05-21 17:20:00,671 thread-8 start to a++
[INFO ] 2010-05-21 17:20:00,671 thread-8 a++ finihed
thread-0:a:13
thread-0:b:6
[INFO ] 2010-05-21 17:20:00,671 thread-0 start to a++
[INFO ] 2010-05-21 17:20:00,671 thread-0 a++ finihed
[INFO ] 2010-05-21 17:20:00,671 thread-9 start to b++
[INFO ] 2010-05-21 17:20:00,671 thread-9 b++ finished
[INFO ] 2010-05-21 17:20:00,671 thread-4 start to b++
[INFO ] 2010-05-21 17:20:00,671 thread-4 b++ finished
[INFO ] 2010-05-21 17:20:00,671 thread-3 start to b++
[INFO ] 2010-05-21 17:20:00,671 thread-3 b++ finished
thread-4:a:14
thread-4:b:9
[INFO ] 2010-05-21 17:20:00,671 thread-4 start to a++
[INFO ] 2010-05-21 17:20:00,671 thread-4 a++ finihed
[INFO ] 2010-05-21 17:20:00,687 thread-7 start to b++
[INFO ] 2010-05-21 17:20:00,687 thread-7 b++ finished
[INFO ] 2010-05-21 17:20:00,687 thread-6 start to b++
[INFO ] 2010-05-21 17:20:00,687 thread-6 b++ finished
thread-2:a:15
thread-2:b:11
[INFO ] 2010-05-21 17:20:00,703 thread-2 start to a++
[INFO ] 2010-05-21 17:20:00,703 thread-2 a++ finihed
[INFO ] 2010-05-21 17:20:00,703 thread-1 start to b++
[INFO ] 2010-05-21 17:20:00,703 thread-1 b++ finished
[INFO ] 2010-05-21 17:20:00,718 thread-0 start to b++
[INFO ] 2010-05-21 17:20:00,718 thread-0 b++ finished
[INFO ] 2010-05-21 17:20:00,718 thread-2 start to b++
[INFO ] 2010-05-21 17:20:00,718 thread-2 b++ finished 


  • 线程加了优先级 , 执行更有序
class Thread的静态属性:         
static int MAX_PRIORITY 
static int MIN_PRIORITY
static int NORM_PRIORITY

** Thread.MAX_PRIORITY = 10
** Thread.NORM_PRIORITY = 5
** Thread.MIN_PRIORITY = 1

主方法main()的优先级是NORM_PRIORITY
例子:
    public static void main(String[] args) {
        MyThread mt = new MyThread();
        Thread t1 = new Thread(mt, "线程A");
        Thread t2 = new Thread(mt, "线程B");
        Thread t3 = new Thread(mt, "线程C");
        t1.setPriority(Thread.NORM_PRIORITY); // 将线程A设置为中等优先级,缺省为5
        t3.setPriority(Thread.MAX_PRIORITY); // 将线程C设置为最高优先级,缺省为10
        t2.setPriority(Thread.MIN_PRIORITY); // 将线程B设置为最低优先级,缺省为1
        t1.start();
        t2.start();
        t3.start();

运行:
D:\java\source\thread\test1>java prioritydemo.PriorityDemo01
线程A线程正在运行。
线程C线程正在运行。
线程B线程正在运行。
线程C线程正在运行。
线程A线程正在运行。
线程B线程正在运行。
线程C线程正在运行。
线程A线程正在运行。
线程B线程正在运行。
线程C线程正在运行。
线程A线程正在运行。
线程B线程正在运行。
线程C线程正在运行。
线程A线程正在运行。
线程B线程正在运行。
线程C线程正在运行。
线程A线程正在运行。


  • 同步方法
计算方法doWrite()上加了synchronized
  public synchronized void doWrite() {
        log.info("start to a++");
        a++;
        log.info("a++ finihed");
        try {
            sleep((int) (Math.random() * 100));
        } catch (InterruptedException e) {
        }

        log.info("start to b++");
        b++;
        log.info("b++ finished");
        try {
            sleep((int) (Math.random() * 100));
        } catch (InterruptedException e) {
        }
  }

  public void print() {
    System.out.println("" + Thread.currentThread().getName() + ":a:" + a);
    System.out.println("" + Thread.currentThread().getName() + ":b:" + b);
  }

    public void run() {
        for (int i = 0; i < 10; i++) {
            doWrite();
            print();
        }
doWrite()已经可以完整执行了,尽管它仍容易被打断,但只会被其他方法打断,不会被其它线程的doWrite()方法打断
方法执行被打断是肯定了,因为线程是基于语句的,不是基于方法的
synchronized是阻止别的线程同一时刻调用方法,而不是阻止别的线程的别的方法(不是本方法)打断本方法

[INFO ] 2010-05-21 17:48:34,343 thread-0 start to a++
[INFO ] 2010-05-21 17:48:34,343 thread-0 a++ finihed
[INFO ] 2010-05-21 17:48:34,390 thread-0 start to b++
[INFO ] 2010-05-21 17:48:34,390 thread-0 b++ finished
thread-0:a:1
[INFO ] 2010-05-21 17:48:34,421 thread-8 start to a++
[INFO ] 2010-05-21 17:48:34,421 thread-8 a++ finihed
thread-0:b:1
[INFO ] 2010-05-21 17:48:34,515 thread-8 start to b++
[INFO ] 2010-05-21 17:48:34,515 thread-8 b++ finished
thread-8:a:2
thread-8:b:2
[INFO ] 2010-05-21 17:48:34,546 thread-6 start to a++
[INFO ] 2010-05-21 17:48:34,546 thread-6 a++ finihed
[INFO ] 2010-05-21 17:48:34,609 thread-6 start to b++
[INFO ] 2010-05-21 17:48:34,609 thread-6 b++ finished
thread-6:a:3
thread-6:b:3
[INFO ] 2010-05-21 17:48:34,703 thread-4 start to a++
[INFO ] 2010-05-21 17:48:34,703 thread-4 a++ finihed
[INFO ] 2010-05-21 17:48:34,765 thread-4 start to b++
[INFO ] 2010-05-21 17:48:34,765 thread-4 b++ finished
thread-4:a:4
thread-4:b:4
[INFO ] 2010-05-21 17:48:34,859 thread-2 start to a++
[INFO ] 2010-05-21 17:48:34,859 thread-2 a++ finihed
[INFO ] 2010-05-21 17:48:34,937 thread-2 start to b++
[INFO ] 2010-05-21 17:48:34,937 thread-2 b++ finished
thread-2:a:5
thread-2:b:5
[INFO ] 2010-05-21 17:48:35,031 thread-9 start to a++
[INFO ] 2010-05-21 17:48:35,031 thread-9 a++ finihed
[INFO ] 2010-05-21 17:48:35,109 thread-9 start to b++
[INFO ] 2010-05-21 17:48:35,109 thread-9 b++ finished
事实上"被打断",很大程度上是因为doWrite()里加了sleep/interrupted语句
如果没有加sleep/interrupted语句,doWrite就很难被print()打断,因为print()在run()方法里是在doWrite()之后执行的。
而doWrite()因为synchronized,实际上被阻塞住了,等于别的线程都阻塞在doWrite(),自然也不执行后边的print()
当然这样一来效率就很低了,同步方法效率都会很低, 因为它阻塞的是别的线程对方法的调用,通常采用的都是同步代码块.


  • 完整的"不被打断"
如果想让各个方法都不被其他线程的"同名"方法打断,就每个方法都加synchronized
    public synchronized void doWrite() {
        log.info("start to a++");
        a++;
        log.info("a++ finihed");

        log.info("start to b++");
        b++;
        log.info("b++ finished");

    }

    public synchronized void print() {
        System.out.println("" + Thread.currentThread().getName() + ":a:" + a);
        System.out.println("" + Thread.currentThread().getName() + ":b:" + b);
    }

    public void run() {
        for (int i = 0; i < 10; i++) {
            doWrite();
            print();
        }
1。每个方法都不会被其他线程的"同名"方法打断
2。但每个方法可能被其他线程的"非同名"方法打断

[INFO ] 2010-05-21 18:22:27,718 thread-0 start to a++
[INFO ] 2010-05-21 18:22:27,718 thread-0 a++ finihed
[INFO ] 2010-05-21 18:22:27,718 thread-0 start to b++
[INFO ] 2010-05-21 18:22:27,718 thread-0 b++ finished
[INFO ] 2010-05-21 18:22:27,718 thread-7 start to a++
[INFO ] 2010-05-21 18:22:27,718 thread-7 a++ finihed
[INFO ] 2010-05-21 18:22:27,718 thread-7 start to b++
[INFO ] 2010-05-21 18:22:27,718 thread-7 b++ finished
[INFO ] 2010-05-21 18:22:27,718 thread-9 start to a++
[INFO ] 2010-05-21 18:22:27,718 thread-9 a++ finihed
[INFO ] 2010-05-21 18:22:27,718 thread-9 start to b++
[INFO ] 2010-05-21 18:22:27,718 thread-9 b++ finished
thread-9:a:3
thread-9:b:3
[INFO ] 2010-05-21 18:22:27,718 thread-9 start to a++
[INFO ] 2010-05-21 18:22:27,718 thread-9 a++ finihed
[INFO ] 2010-05-21 18:22:27,718 thread-9 start to b++
[INFO ] 2010-05-21 18:22:27,718 thread-9 b++ finished
thread-9:a:4
thread-9:b:4
[INFO ] 2010-05-21 18:22:27,718 thread-9 start to a++
[INFO ] 2010-05-21 18:22:27,718 thread-9 a++ finihed
[INFO ] 2010-05-21 18:22:27,718 thread-9 start to b++
[INFO ] 2010-05-21 18:22:27,718 thread-9 b++ finished 


  • 极端的"不被打断" ----连"被其他线程非同名方法打断"的情况都禁止掉
在run方法上也加synchronized
    public synchronized void run() {
        for (int i = 0; i < 10; i++) {
            doWrite();
            print();
        }
    }
这样其实已经不是”并发“了,只有一个线程run方法全部执行完,其他线程run()才开始执行,实际上成了”顺序“执行
[INFO ] 2010-05-21 18:26:10,906 thread-0 start to a++
[INFO ] 2010-05-21 18:26:10,906 thread-0 a++ finihed
[INFO ] 2010-05-21 18:26:10,906 thread-0 start to b++
[INFO ] 2010-05-21 18:26:10,906 thread-0 b++ finished
thread-0:a:1
thread-0:b:1
[INFO ] 2010-05-21 18:26:10,906 thread-0 start to a++
[INFO ] 2010-05-21 18:26:10,906 thread-0 a++ finihed
[INFO ] 2010-05-21 18:26:10,921 thread-0 start to b++
[INFO ] 2010-05-21 18:26:10,921 thread-0 b++ finished
thread-0:a:2
thread-0:b:2
[INFO ] 2010-05-21 18:26:10,921 thread-0 start to a++
[INFO ] 2010-05-21 18:26:10,921 thread-0 a++ finihed
[INFO ] 2010-05-21 18:26:10,921 thread-0 start to b++
[INFO ] 2010-05-21 18:26:10,921 thread-0 b++ finished
thread-0:a:3
thread-0:b:3
[INFO ] 2010-05-21 18:26:10,921 thread-0 start to a++
[INFO ] 2010-05-21 18:26:10,921 thread-0 a++ finihed
[INFO ] 2010-05-21 18:26:10,921 thread-0 start to b++
[INFO ] 2010-05-21 18:26:10,921 thread-0 b++ finished
thread-0:a:4
thread-0:b:4
[INFO ] 2010-05-21 18:26:10,921 thread-0 start to a++
[INFO ] 2010-05-21 18:26:10,921 thread-0 a++ finihed
[INFO ] 2010-05-21 18:26:10,921 thread-0 start to b++
[INFO ] 2010-05-21 18:26:10,921 thread-0 b++ finished
thread-0:a:5
thread-0:b:5
[INFO ] 2010-05-21 18:26:10,921 thread-0 start to a++
[INFO ] 2010-05-21 18:26:10,921 thread-0 a++ finihed
[INFO ] 2010-05-21 18:26:10,921 thread-0 start to b++
[INFO ] 2010-05-21 18:26:10,921 thread-0 b++ finished
thread-0:a:6
thread-0:b:6

 
  • join()方法——————让线程真正按启动顺序执行,必须等start()的运行完成后才继续运行后面的语句, 也是一种"顺序"执行
例子:
假设线程MyThread的功能是打印0-99
public class Test {
 public static void main(String[] args) throws Exception{
  MyThread mt = new MyThread();
  mt.start();
   System.out.println(101); 
 }
}
输出其实是:
101,0,...99
现在加入join()方法
public class Test {
 public static void main(String[] args) throws Exception{
  MyThread mt = new MyThread();
  mt.start();
  mt.join();     
  System.out.println(101);
 }
}
输出:
0,...99,101 















    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多