• JAVA并发编程1_多线程的实现方式


    JAVA中创建线程的两种方式:继承Thread或实现Runnable接口。

    1 继承Thread类,重写run方法:

    /**
     * 实现线程的第一种方式 :继承Thread
     * 实现数据共享需要设置属性为静态
     * @author qhyuan1992
     *
     */
    class MyThread extends Thread{
    	private int count;// static
    	public MyThread(String id){
    		super(id);
    	}
    	public void run() {
    		while (count < 5) {
    			count ++;
    			System.out.println(currentThread() + "--->" + count);
    		}
    	}
    }
    class Test{
    	public static void main(String[] args) {
    		Thread t1 = new MyThread("thread_1");
    		Thread t2 = new MyThread("thread_2");
    		t1.start();
    		t2.start();
    	}
    }
    // output(未共享资源)
    //Thread[thread_1,5,main]--->1
    //Thread[thread_2,5,main]--->1
    //Thread[thread_1,5,main]--->2
    //Thread[thread_1,5,main]--->3
    //Thread[thread_1,5,main]--->4
    //Thread[thread_2,5,main]--->2
    //Thread[thread_1,5,main]--->5
    //Thread[thread_2,5,main]--->3
    //Thread[thread_2,5,main]--->4
    //Thread[thread_2,5,main]--->5
    

    2 实现Runnable接口,重写run方法,作为参数传给Thread对象。

    /**
     * 实现线程的第二种方式 :实现Runnable接口
     * 实现数据共享
     * @author qhyuan1992
     */
    class MyRunnable implements Runnable{
    	private int count;
    	public void run() {
    		while (count < 5) {
    			count ++;
    			System.out.println(Thread.currentThread() + "--->" + count);
    		}
    	}
    	public static void main(String[] args) {
    		MyRunnable runnable = new MyRunnable();
    		Thread t1 = new Thread(runnable);
    		Thread t2 = new Thread(runnable);
    		t1.start();
    		t2.start();
    	}
    }
    // output(使用同一个Runnable对象构造Thread对象实现资源共享)
    //Thread[Thread-0,5,main]--->2
    //Thread[Thread-1,5,main]--->2
    //Thread[Thread-1,5,main]--->3
    //Thread[Thread-1,5,main]--->4
    //Thread[Thread-1,5,main]--->5
    


    两种方式有何区别?查看源代码可以看到,Thread类是实现了Runnable接口的。

    public
    class Thread implements Runnable {
        …
        /* What will be run. */
        private Runnable target; // target就是我们使用第二种方法的时候传递的runnable对象
    
        /* The group of this thread */
    private ThreadGroup group;
    …
    public Thread(Runnable target) {//第二种使用线程的方式的构造函数
        init(null, target, "Thread-" + nextThreadNum(), 0);
     }
    }
    

    当调用Thread类的start()方法时,会调用本地方法start0();

    public synchronized void start() {
    ……
            boolean started = false;
            try {
                start0();
                started = true;
            } finally {
                ……
            }
        }
    private native void start0();
    

    总之,会辗转调用到run方法:

     /**
         * If this thread was constructed using a separate
         * <code>Runnable</code> run object, then that
         * <code>Runnable</code> object's <code>run</code> method is called;
         * otherwise, this method does nothing and returns.
         * <p>
         * Subclasses of <code>Thread</code> should override this method.
         *
         * @see     #start()
         * @see     #stop()
         * @see     #Thread(ThreadGroup, Runnable, String)
         */
        @Override
        public void run() {
            if (target != null) {
                target.run();
            }
    }
    

    如果使用Runnable来构造Thread的话,将调用Runnable对象的run方法;否则,什么也不做。但通过继承的方式来实现线程,由于多态根本没有执行Thread类中的run方法,就会执行重写的run方法。

    例如:要是继承自Thread实现了run方法,也通过了Runnable来构造Thread结果会执行哪个run方法呢?答案是确定的:会执行我们写在继承自Thread类中的run方法。

    class MyRunnable implements Runnable{
    public void run() {
    	System.out.println("MyRunnable");
    	}
    }
    
    class MyThread extends Thread{
    	public MyThread(Runnable r){
    		super(r);
    	}
    	public void run() {
    		System.out.println("MyThread");
    	}
    }
    
    class Test{
    	public static void main(String[] args) {
    		Thread t = new MyThread(new MyRunnable());
    		t.start();
    	}
    }
    // output:
    //MyThread
    


    到底使用Thread还是Runnable?

    实现Runnable接口比继承Thread类所具有的优势:

    1.适合多个相同的程序代码的线程去处理同一个资源,继承Thread的需要将共享的资源设置为static。

    2.可以避免java中的单继承的限制

    3.增加程序的健壮性,代码可以被多个线程共享,代码和数据独立。

    将第一个代码的count字段改为static
    class MyThread extends Thread{
    	private static int count;// static
    	public MyThread(String id){
    		super(id);
    	}
    	public void run() {
    		while (count < 5) {
    			count ++;
    			System.out.println(currentThread() + "--->" + count);
    		}
    	}
    }
    class Test{
    	public static void main(String[] args) {
    		Thread t1 = new MyThread("thread_1");
    		Thread t2 = new MyThread("thread_2");
    		t1.start();
    		t2.start();
    	}
    }
    
    // output (结果不确定)
    //Thread[thread_1,5,main]--->2
    //Thread[thread_2,5,main]--->2
    //Thread[thread_2,5,main]--->3
    //Thread[thread_2,5,main]--->4
    //Thread[thread_2,5,main]--->5
    

    可以看到使用static的方式也可以共享资源,和使用第二种方式实现多线程一样,前提是创建Thread的Runnable对象是同一个。


    细心一点可以看到打印的结构不是我们所预期的,例如:

    //Thread[thread_1,5,main]--->2

    //Thread[thread_2,5,main]--->2

    出现这样的结果就是因为多线程并发的不可控性,关于线程同步这个问题会在后面继续探讨。

  • 相关阅读:
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    svn 启动项目报错,项目被lock
    BigDecimal 用法详解
    MySQL 规范
    Tomcat 详解URL请求
    Tomcat Servlet工作原理
    Tomcat Context容器和Wrapper容器
    Tomcat 核心组件 Container容器相关
    Tomcat 核心组件 Connector
  • 原文地址:https://www.cnblogs.com/qhyuan1992/p/5385312.html
Copyright © 2020-2023  润新知