最近在博客园中逛,看到多线程想学习一下,虽然作者本人感觉挺详细的,但对于新手没学过多线程理解还是有难度的,最多也就是明白大概意思,自己写还是一片空白,我看过多个博客以后觉得还需要打代码才能彻底理解多线程,以下以一个经典多线程题目为例,一个菜鸟解题的具体步骤:

  题目:建立三个线程,A线程打印10次A,B线程打印10次B,C线程打印10次C,要求线程同时运行,交替打印10次ABC。

  1.看到三个线程,同时运行,交替打印,和大神解答写的各种流程、sleep、synchronized、wait、notify一阵头痛。还是自己慢慢来,打印10个A先。。

 

package main;

/**
 * 
 * 多线程题目解答
 * @author 光
 * @version 2015年11月20日 上午10:46:53
 *
 */
public class ManyThreadPrint implements Runnable {
    
    public String name;
    
    public ManyThreadPrint(String name){
        this.name=name;
    }

    @Override
    public void run() {
        int count = 10;
        while(count > 0){
            System.out.print(name);
            count--;
        }
    }

    public static void main(String[] args) {
        ManyThreadPrint mtpa = new ManyThreadPrint("A");
        new Thread(mtpa).start();
    }
}

  解析:使用实现Runnable接口的方式使用线程,main方法中添加实例使用构造器传参A,重写run()方法中循环打印10次

  运行结果如下:

AAAAAAAAAA

  2.十次A打印完成,哈哈,把B和C打印以下试试

package main;

/**
 * 
 * 多线程题目解答
 * @author 光
 * @version 2015年11月20日 上午10:46:53
 *
 */
public class ManyThreadPrint implements Runnable {
    
    public String name;
    
    public ManyThreadPrint(String name){
        this.name=name;
    }

    @Override
    public void run() {
        int count = 10;
        while(count > 0){
            System.out.print(name);
            count--;
        }
    }

    public static void main(String[] args) {
        ManyThreadPrint mtpa = new ManyThreadPrint("A");
        ManyThreadPrint mtpb = new ManyThreadPrint("B");
        ManyThreadPrint mtpc = new ManyThreadPrint("C");
        new Thread(mtpa).start();
        new Thread(mtpb).start();
        new Thread(mtpc).start();
    }
}

  解析:只是在main方法中添加两个实例把B和C穿进去,添加两个线程执行

  运行结果如下:

AAAAAAAAAABBBBBBBBBBCCCCCCCCCC

  手贱又运行一下:

AAAAAAAAAACCCCCCCCCCBBBBBBBBBB

  这怎么回事。。在试一下:

ABBBBBBBBBBAAAAAAAAACCCCCCCCCC

  好吧,结果10个A,10个B,10个C全部打印出来了,就是结果不固定。

  3.查了一下资料,原来是3个线程同时执行,顺序不固定。只好让后面的线程先等一下再执行:

package main;

/**
 * 
 * 多线程题目解答
 * @author 光
 * @version 2015年11月20日 上午10:46:53
 *
 */
public class ManyThreadPrint implements Runnable {
    
    public String name;
    
    public ManyThreadPrint(String name){
        this.name=name;
    }

    @Override
    public void run() {
        int count = 10;
        while(count > 0){
            System.out.print(name);
            count--;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ManyThreadPrint mtpa = new ManyThreadPrint("A");
        ManyThreadPrint mtpb = new ManyThreadPrint("B");
        ManyThreadPrint mtpc = new ManyThreadPrint("C");
        new Thread(mtpa).start();
        Thread.sleep(10);
        new Thread(mtpb).start();
        Thread.sleep(10);
        new Thread(mtpc).start();
        Thread.sleep(10);
    }
}

  解析:有一点需要注意,Thread.sleep(10);是下一个线程启动需要等待的时间,由于最后结果需要交替打印,所以第三个线程执行后也有一个等待,相当于下轮的第一个线程等待。

  结果如下(执行几次都一样):

AAAAAAAAAABBBBBBBBBBCCCCCCCCCC

  3.接下来就是交替ABC按照大神的方法,建立3个对象,虽然是三个普通的Object,却在run()中通过同步、等待、释放锁来实现线程的执行顺序,先看一下代码:

package main;

/**
 * 
 * 多线程题目解答
 * @author 光
 * @version 2015年11月20日 上午10:46:53
 *
 */
public class ManyThreadPrint implements Runnable {
    
    public String name;
    public Object prev;
    public Object self;
    
    public ManyThreadPrint(String name, Object prev, Object self) {
        this.name = name;
        this.prev = prev;
        this.self = self;
    }


    @Override
    public void run() {
        int count = 10;
        while(count > 0){
            synchronized (prev) {
                synchronized (self) {
                    System.out.print(name);
                    count--;
                    self.notify();
                }
                try {
                    prev.wait();
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            
        }
    }

    public static void main(String[] args) throws InterruptedException {
        Object a = new Object(); 
        Object b = new Object();
        Object c = new Object();
        ManyThreadPrint mtpa = new ManyThreadPrint("A",c,a);
        ManyThreadPrint mtpb = new ManyThreadPrint("B",a,b);
        ManyThreadPrint mtpc = new ManyThreadPrint("C",b,c);
        new Thread(mtpa).start();
        Thread.sleep(10);
        new Thread(mtpb).start();
        Thread.sleep(10);
        new Thread(mtpc).start();
        Thread.sleep(10);
    }
}

  解析:

  改变构造器,每次创建实例是除了打印的字符串,还有两个对象,这一点要注意,这两个对象只是普通的Object,跟线程没一毛线关系,只是通过线程对对象锁的操作来控制流程。关键代码在run()中的循环里面,一点一点来。

  这里synchronized (self)、synchronized (prev),self当前对象锁,prev前一个(前缀)对象锁,当线程获取两个对象锁时执行打印;需要注意。将synchronized (self)放入synchronized (prev)中表示打印A线程执行后,进入等待前置C对象的线程池里面,这样在打印C时唤醒一下C对象,那么打印C完成后就会立刻打印A,不过这样执行需要保证3个线程的启动顺序,即main方法中的Thread.sleep(10)。启动打印A线程时,打印A,唤醒自己,进入等待C的线程池,释放AC。当3个线程按照启动顺序完成时,即打印C线程完成后,会立刻打印A,打印A线程完成后,立刻打印B,依照顺序循环。

  也就是说,在3个线程启动完成后,已经将打印A的线程进入等待C对象的线程池里;将打印B的线程进入等待A对象的线程池里;将打印C的线程进入等待B对象的线程池里。这时按照打印A线程、打印B线程、打印C线程的顺序执行,就保证下一轮以打印A线程开始,从而保证以后打印顺序。

  在自己打代码的过程中发现了很多感觉看懂的时候没发现的东西,所以,学东西,最好自己要手打一遍。

posted on 2015-11-24 15:45  小光  阅读(5830)  评论(7编辑  收藏  举报