java多线程-Thread,Runnable的实现(三)

Date: 2017-04-12 10:10:17

java多线程-Thread,Runnable的实现(三)

java需要实现多线程的方法有两种:
继承Thread,或者实现Runnabel接口。

Thread

package cn.thread.first.thread;

class MyThread extends Thread {

    private int temp;

    public MyThread(int temp) {
        this.temp = temp;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("system out Thead" + temp);
    }

}


public class ThreadDome {


    public static void main(String orgs[]) {
        MyThread myThread = new MyThread(1);
        myThread.start();//异步调用
        //myThread.run();//同步调用

        MyThread myThread2 = new MyThread(2);
        myThread2.start();//代码顺序,不能代表线程启动的顺序
        System.out.println("运行完毕");

    }

}

运行完毕
system out Thead1
system out Thead2

Thread.java类中的start方法通知了“线程规划器”,此线程已经准备就绪,等待调用线程对象的run方法。如果直接调用run方法,则会执同步调用,因为没有通知“线程规划器”,而是直接调用了run方法。

currentThread与this

Thread.currentThread():返回的是当前运行的线程实例;
this:说的是当前对象线程的实例。

用一段代码来说明比较会清楚点:


class OperateTest extends Thread {

    public OperateTest() {
        System.out.println("OperateTest---begin");
        System.out.println("Thread.currentThread().getName()=" + Thread.currentThread().getName() + ",this=" + this.getName());
        System.out.println("Thread.currentThread().isAlive()=" + Thread.currentThread().isAlive() + ",this=" + this.isAlive());
        System.out.println("Thread.currentThread()==this =" + (Thread.currentThread() == this));
        System.out.println("OperateTest---end ");
        System.out.println();
    }

    @Override
    public void run() {
        System.out.println("run---begin");
        System.out.println("Thread.currentThread().getName=" + Thread.currentThread().getName() + ",this=" + this.getName());
        System.out.println("Thread.currentThread().isAlive()=" + Thread.currentThread().isAlive() + ",this=" + this.isAlive());
        System.out.println("Thread.currentThread()==this =" + (Thread.currentThread() == this));
        System.out.println("run --- end");
        System.out.println();
    }
}

public class ThreadCurruentDome {
    public static void main(String[] args) {

        Thread thread1 = new OperateTest();
        thread1.start();

        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Thread thread2 = new Thread(thread1);
        System.out.println("main begin thread2 isAlive=" + thread2.isAlive());
        thread2.setName("A");
        thread2.start();
        System.out.println("main end thread2 isAlive=" + thread2.isAlive());

    }
}

输出结果:
OperateTest—begin
Thread.currentThread().getName()=main,this=Thread-0
Thread.currentThread().isAlive()=true,this=false
Thread.currentThread()==this =false
OperateTest—end

run—begin
Thread.currentThread().getName=Thread-0,this=Thread-0
Thread.currentThread().isAlive()=true,this=true
Thread.currentThread()==this =true
run — end

main begin thread2 isAlive=false
run—begin
main end thread2 isAlive=true
Thread.currentThread().getName=A,this=Thread-0
Thread.currentThread().isAlive()=true,this=false
Thread.currentThread()==this =false
run — end

先看第一个OperateTest—begin-end这里;
Thread thread1 = new OperateTest();
实例化时产生的日志,实例化的代码是在main方法里面执行的,main方法是在main这个主线程里面的.
Thread.currentThread().getName()返回的main线程的名字,当前运行的线程是主线程;
this.name=Thread-0;this.isAlive=false;这个返回的是OperateTest()这个对象thread1的线程,thread1线程此刻还没有执行start(),所以thread1对象线程是false;

这里说明了,Thread.currentThread()返回的是当前运行的线程实例;this关键字返回的是当前对象线程实例。

再看第一个run—begin。
thread1.start();
第一个run-begin-end是start()执行时打印的日志。
这个时候Thread.currentThread()==this =true。
原因:Thread.currentThread()表示当前正在运行的线程,那就是thread1啊。thread1执行了start。而this上面就说了表示thread1这个对象线程的实例;所以这个时候Thread.currentThread()和this正好都指向了thread1线程了。

看最后一个run—begin—-end
thread2.start();
Thread.currentThread()表示当前正在执行的线程哦,那现在时threa2正在执行,所以就表示thread2了没什么好说的。
this这个时候表示什么呢?还是threa1这个对象,为什么?看代码:
Thread thread2 = new Thread(thread1);
这个时候threa1已经执行完毕了,所以this.isAlive=false,因为thread1已经执行完毕了。

总结

Thread.currentThread()返回的是当前运行的线程实例;
this关键字返回的是当前对象线程实例。
Thread.currentThread()和对象无关,和当前执行的线程有关,他表示的是正在执行的线程。而this和当前对象挂钩,表示的是当前对象。上面的试例中this一直指向的是Thread thread1 = new OperateTest(); thread1这个对象。

在获取线程情况的时候总是使用Thread.currentThread(),而不要使用this哦,因为this是和对象挂钩的,Thread.currentThread()才是获取当前正在执行的线程哦。

实现Runnable接口

package cn.thread.first.runnable;

public class RunnableDemo implements Runnable {
    Thread t;

    RunnableDemo() {
        t = new Thread(this, "demo thread");
        System.out.println("Child thread start :" + t);
        t.start();
    }

    public void run() {
        try {
            for (int i = 1; i < 5; i++) {
                System.out.println("Child thread :" + i);
                Thread.sleep(50);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

class ThreadDemo{
    public static void main(String args[]){
        new RunnableDemo();
        try{
            for(int i=0;i<5;i++){
                System.out.println("main thread :" + i);
                Thread.sleep(100);
            }
        }catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

线程优先级

在各种各样的线程中,Java虚拟机必须实现一个有优先权的、基于优先级的调度程序。这意味着Java程序中的每一个线程被分配到一定的优先权,使用定义好的范围内的一个正整数表示。优先级可以被开发者改变。即使线程已经运行了一定时间,Java虚拟机也不会改变其优先级优先级的值很重要,因为Java虚拟机和下层的操作系统之间的约定是操作系统必须选择有最高优先权的Java线程运行。所以我们说Java实现了一个基于优先权的调度程序。该调度程序使用一种有优先权的方式实现,这意味着当一个有更高优先权的线程到来时,无论低优先级的线程是否在运行,都会中断(抢占)它。这个约定对于操作系统来说并不总是这样,这意味着操作系统有时可能会选择运行一个更低优先级的线程。

这里说的由操作系统最终决定优先执行哪个线程,说明你设置了线程优先权,但并不代表你就一定会最先执行,它还取决于调度程序,系统优化之类等。

理解线程的优先权

  1. 记住当线程的优先级没有指定时,所有线程都携带普通优先级。
  2. 优先级可以用从1到10的范围指定。10表示最高优先级,1表示最低优先级,5是普通优先级。
  3. 记住优先级最高的线程在执行时被给予优先。但是不能保证线程在启动时就进入运行状态。
  4. 与在线程池中等待运行机会的线程相比,当前正在运行的线程可能总是拥有更高的优先级。
  5. 调度程序决定哪一个线程被执行。
  6. t.setPriority()用来设定线程的优先级。
  7. 记住在线程开始方法被调用之前,线程的优先级应该被设定。
  8. 你可以使用常量,如MIN_PRIORITY,MAX_PRIORITY,NORM_PRIORITY来设定优先级
package cn.thread.first.thread;

public class ThreadPriority {

    public static void main(String[] args)
    {
        Thread producer = new Producer();
        Thread consumer = new Consumer();

        producer.setPriority(Thread.MAX_PRIORITY);//最高优先级
        consumer.setPriority(Thread.MIN_PRIORITY);//最低优先级

        producer.start();
        consumer.start();
    }


}

class Producer extends Thread
{
    public void run()
    {
        for (int i = 0; i < 5; i++)
        {
//            try {
//                Thread.sleep(100);
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
            System.out.println("I am Producer : Produced Item " + i);

        }
    }
}

class Consumer extends Thread
{
    public void run()
    {
        for (int i = 0; i < 5; i++)
        {
            System.out.println("I am Consumer : Consumed Item " + i);

        }
    }
}

输出结果:
I am Producer : Produced Item 0
I am Producer : Produced Item 1
I am Producer : Produced Item 2
I am Producer : Produced Item 3
I am Producer : Produced Item 4
I am Consumer : Consumed Item 0
I am Consumer : Consumed Item 1
I am Consumer : Consumed Item 2
I am Consumer : Consumed Item 3
I am Consumer : Consumed Item 4

把Producer里面的sleep打开后,发现执行结果正好相反,说明操作系统调度时,发现Producer执行时间过长。

不要把线程优先级与运行结果的顺序作为衡量的标准,优先级较高的线程并不一定每次都先执行完run()方法分中的任务,也就是线程优先级与run方法执行结果没有相关性,他们之间具有不确定性和随机性。

yield()方法使用示例

yield意味着放手,放弃。一个调用yield()方法的线程告诉虚拟机它乐意让其他线程占用自己的位置。这表明该线程没有在做一些紧急的事情。注意,这仅是一个暗示,并不能保证不会产生任何影响

yield不会线程挂起就是说yield不会交出CPU调度使用权,只是对其他线程进行客气的说,要不你先执行吧,只是对其他线程的一种礼貌让行。

package cn.thread.first.thread;

public class ThreadPriority {

    public static void main(String[] args)
    {
        Thread producer = new Producer();
        Thread consumer = new Consumer();

        producer.setPriority(Thread.MAX_PRIORITY);
        consumer.setPriority(Thread.MIN_PRIORITY);

        producer.start();
        consumer.start();
    }


}

class Producer extends Thread
{
    public void run()
    {
        for (int i = 0; i < 5; i++)
        {
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("I am Producer : Produced Item " + i);

        }
    }
}

class Consumer extends Thread
{
    public void run()
    {
        for (int i = 0; i < 5; i++)
        {
            System.out.println("I am Consumer : Consumed Item " + i);
            Thread.yield();

        }
    }
}

输出结果:
I am Consumer : Consumed Item 0
I am Producer : Produced Item 0
I am Consumer : Consumed Item 1
I am Consumer : Consumed Item 2
I am Consumer : Consumed Item 3
I am Consumer : Consumed Item 4
I am Producer : Produced Item 1
I am Producer : Produced Item 2
I am Producer : Produced Item 3
I am Producer : Produced Item 4
Producer拥有最高优先权,而且Consumer 还主动告诉CPU自己可以愿意交出CPU使用优先级,让其他线程优先吧,但时结果还是这样,Thread.yield()只是暗示一下,并不代表一定会产生什么影响。

守护线程

java线程中有两种线程:用户线程,守护线程。
守护线程是一种特殊线程,它的特性有“陪伴”的含义,当进程中不存在非守护线程了,则守护线程自动销毁。
典型的守护线程就是垃圾回收线程,当进程中没有非守护线程时,守护线程就会自动销毁。

猜你喜欢

转载自blog.csdn.net/piaoslowly/article/details/81475928