java Thread的探索(一)

来源:互联网 发布:无法访问家庭网络共享 编辑:程序博客网 时间:2024/06/11 21:38

一、总结一下Thread的方法

1.Thread的构造函数

1.1 Thread():无参构造

1.2 Thread(Runnable target)

1.3 Thread(ThreadGroup group ,Runnabletarget)

1.4 Thread(String name)

1.5 Thread(Runnable target,String name)

1.6 Thread(ThreadGroup group, Runnabletarget,String name)

1.7 Thread(ThreadGroup group,Runnabletarget,String name,long stactSize)

 参数group:线程组

    target:Runnable对象

    name:线程名

         stactSize:线程所需堆栈大小,如果为零表示忽略

2. Thread的静态方法:

2.1 currentThread():返回对当前执行对象的引用;

2.2 yield():执行yield()提示当前线程调度器愿意放弃当前所使用的处理器,当然调度器可以忽略这个提示(可以理解为你想让当前线程让步,但是愿不愿意让,具有不确定性)。

2.3 sleep(long millis):当前的线程以指定的毫秒数休眠(暂时停止执行),线程不会失去监视器的所有权(可以理解为不会释放该线程持有的对象锁),sleep(long millis),内部调用了sleep(long millis,int nanos)方法;

2.4 sleep(long millis,int nanos):当前的正在执行的线程以指的毫秒数(ms)加纳秒数(ns)休眠(暂时停止执行),线程不会失去监视器的所有权(1ms=106ns精度很高);

2.5 interrupted():测试当前线程是否被暂停,此方法清除线程的暂停状态。

3.Thread的非静态方法

3.1 start():线程执行方法,重复执行将会thrownew IllegalArgumentException,这是一个synchronized方法

3.2 interrupt():暂停该线程

3.3 isInterrupted():判断线程是否为暂停状态,线程的状态不受此方法的影响;

3.4 isAlive():判断线程是否活着的

3.5 setPriority(int newPriority):设置线程的优先级,默认优先级为5,最小为1,最大为10

3.6 getPriority():获取线程的优先级;

3.7 setName(String name):设置线程名;

3.8 getName():获取线程名;

3.9 getThreadGroup():获取线程组

3.10 activeCount():返回当前线程及其子组线程中活动线程的估计值;

3.11 enumerate(Thread array[]):将当前的线程组及其子组中的每个活动线程复制到指定数组中,并返回放入线组的线程数;

3.12 join(long millis):等待此线程最多mills或者此线程在mills内结束。

  join():等待此线程结束,内部调用的join(0);

join(long mills,int nanos):这个方法内部调用了join(longmills),只是等待时间为 mills+nanos;

3.13 setDaemon(boolean on):将此线程是否设置为守护线程,此方法必须在start()之前设置,否则报错;

3.14 isDaemon():判断此线程是否为守护线程;

3.15 checkAccess():确认当前线程是否有修改此线程的权限

3.16 getId():返回当前线程的id;

3.17 getState():返回当前线程的状态State.

 二、实际操作

   说一千道一万,不如自己来实际操作一下。首先来测试线程的暂停状态,先来看下一般的异常抛出

代码如下:

 @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Thread thread = new Thread(new Runnable() {            @Override            public void run() {                for (int i = 0; i < 10; i++) {                    File file = new File(Environment.getExternalStorageDirectory() + "/abcdef");                    try {                        FileInputStream in = new FileInputStream(file);                    } catch (FileNotFoundException e) {                        e.printStackTrace();                    }                    try {                        Thread.sleep(1000);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        });        thread.start();    }empty运行结果08-17 11:13:03.425 6531-6573/threaddemo2 W/System.err: java.io.FileNotFoundException: /storage/emulated/0/abcdef: open failed: ENOENT (No such file or directory)08-17 11:13:03.425 6531-6573/threaddemo2 W/System.err:     at libcore.io.IoBridge.open(IoBridge.java:452)08-17 11:13:03.425 6531-6573/threaddemo2 W/System.err:     at java.io.FileInputStream.(FileInputStream.java:76)08-17 11:13:03.425 6531-6573/threaddemo2 W/System.err:     at com.wogu.threaddemo2.MainActivity$1.run(MainActivity.java:26)08-17 11:13:03.425 6531-6573/threaddemo2 W/System.err:     at java.lang.Thread.run(Thread.java:818)08-17 11:13:03.425 6531-6573/threaddemo2 W/System.err: Caused by: android.system.ErrnoException: open failed: ENOENT (No such file or directory)08-17 11:13:03.425 6531-6573/threaddemo2 W/System.err:     at libcore.io.Posix.open(Native Method)08-17 11:13:03.425 6531-6573/threaddemo2 W/System.err:     at libcore.io.BlockGuardOs.open(BlockGuardOs.java:186)08-17 11:13:03.425 6531-6573/threaddemo2 W/System.err:     at libcore.io.IoBridge.open(IoBridge.java:438)08-17 11:13:03.425 6531-6573/threaddemo2 W/System.err: ... 3 more08-17 11:13:04.466 6531-6573/threaddemo2 W/System.err: java.io.FileNotFoundException: /storage/emulated/0/abcdef: open failed: ENOENT (No such file or directory)08-17 11:13:04.466 6531-6573/threaddemo2 W/System.err:     at libcore.io.IoBridge.open(IoBridge.java:452)08-17 11:13:04.466 6531-6573/threaddemo2 W/System.err:     at java.io.FileInputStream.(FileInputStream.java:76)08-17 11:13:04.466 6531-6573/threaddemo2 W/System.err:     at com.wogu.threaddemo2.MainActivity$1.run(MainActivity.java:26)08-17 11:13:04.466 6531-6573/threaddemo2 W/System.err:     at java.lang.Thread.run(Thread.java:818)

可以看到文件路径不存在,该线程每秒抛出一个FileNotFoundException异常

再看下thread2被暂停后会出现什么结果

empty    private static final String TAG = "MainActivity";    private Thread thread1;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        thread1 = new Thread(new Runnable() {            @Override            public void run() {                for (int i = 0; i < 10; i++) {                    Log.i(TAG, "当前线程名:" + Thread.currentThread().getName());                    try {                        Thread.sleep(1000);                    } catch (InterruptedException e) {                        e.printStackTrace();                    }                }            }        }, "thread1");        thread1.start();        //建立一个定时器2秒后暂停线程thread1        TimerTask task = new TimerTask() {            @Override            public void run() {                Log.i(TAG, "线程暂停前状态:" + thread1.isInterrupted());                thread1.interrupt();                Log.i(TAG, "线程暂停后状态:" + thread1.isInterrupted());            }        };        Timer timer=new Timer("checkThreadState");        timer.schedule(task,2000);    }empty测试结果11:31:21.237 25594-25664/threaddemo2 I/MainActivity: 当前线程名:thread108-17 11:31:22.238 25594-25664/threaddemo2 I/MainActivity: 当前线程名:thread108-17 11:31:22.239 25594-25665/threaddemo2 I/MainActivity: 线程暂停前状态:false08-17 11:31:22.239 25594-25665/threaddemo2 I/MainActivity: 线程暂停后状态:true08-17 11:31:22.239 25594-25664/threaddemo2 W/System.err: java.lang.InterruptedException08-17 11:31:22.241 25594-25664/threaddemo2 W/System.err:     at java.lang.Thread.sleep(Native Method)08-17 11:31:22.241 25594-25664/threaddemo2 W/System.err:     at java.lang.Thread.sleep(Thread.java:1031)08-17 11:31:22.241 25594-25664/threaddemo2 W/System.err:     at java.lang.Thread.sleep(Thread.java:985)08-17 11:31:22.241 25594-25664/threaddemo2 W/System.err:     at com.wogu.threaddemo2.MainActivity$1.run(MainActivity.java:25)08-17 11:31:22.241 25594-25664/threaddemo2 W/System.err:     at java.lang.Thread.run(Thread.java:818)08-17 11:31:22.241 25594-25664/threaddemo2 I/MainActivity: 当前线程名:thread108-17 11:31:23.241 25594-25664/threaddemo2 I/MainActivity: 当前线程名:thread108-17 11:31:24.242 25594-25664/threaddemo2 I/MainActivity: 当前线程名:thread108-17 11:31:25.242 25594-25664/threaddemo2 I/MainActivity: 当前线程名:thread108-17 11:31:26.242 25594-25664/threaddemo2 I/MainActivity: 当前线程名:thread108-17 11:31:27.242 25594-25664/threaddemo2 I/MainActivity: 当前线程名:thread108-17 11:31:28.243 25594-25664/threaddemo2 I/MainActivity: 当前线程名:thread1

thread2.isInterrupted()调用此方法后,查看日志后可以看到thread2的确暂停了,但是为什么只抛出一次InterruptedException异常。看了下Thread类,突然发现sleep(long millis,int nanos)调用了Thread.interrupted()方法(查看下),该方法具有清除了thread2线程的暂停状态的作用,所以第二次不会再出现异常。

emptypublic static void sleep(long millis, int nanos)    throws InterruptedException {        if (millis < 0) {            throw new IllegalArgumentException("millis < 0: " + millis);        }        if (nanos < 0) {            throw new IllegalArgumentException("nanos < 0: " + nanos);        }        if (nanos > 999999) {            throw new IllegalArgumentException("nanos > 999999: " + nanos);        }        // The JLS 3rd edition, section 17.9 says: "...sleep for zero        // time...need not have observable effects."        if (millis == 0 && nanos == 0) {            // ...but we still have to handle being interrupted.            //此处调用了Thread.interrupted()            if (Thread.interrupted()) {              throw new InterruptedException();            }            return;        }        long start = System.nanoTime();        long duration = (millis * NANOS_PER_MILLI) + nanos;        Object lock = currentThread().lock;        // Wait may return early, so loop until sleep duration passes.        synchronized (lock) {            while (true) {                sleep(lock, millis, nanos);                long now = System.nanoTime();                long elapsed = now - start;                if (elapsed >= duration) {                    break;                }                duration -= elapsed;                start = now;                millis = duration / NANOS_PER_MILLI;                nanos = (int) (duration % NANOS_PER_MILLI);            }        }    }

  再来看看join这个重载方法,join这个重载方法,归根结底还是join(long millis)Join(long millis)内部是一个synchronizedlock{},lockObject对象,这就意味着Activity中所有其他线程都将暂停。直到获得Object对象锁的线程在设定的时间内已经结束,或者超过设定的时间(换句话来说就是等到该线程释放了Object对象锁)。代码如下:

empty @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        TestThread testThread=new TestThread();        Thread thread2=new Thread(testThread,"Thread2");        thread2.start();        //主线程每秒打印一次        for (int i = 0; i < 5; i++) {            Log.i(TAG, "当前线程名:" + Thread.currentThread().getName());            try {                Thread.sleep(1000);            } catch (InterruptedException e) {                e.printStackTrace();            }        }          }    private class TestThread implements Runnable{        @Override        public void run() {            for (int i = 0; i < 5; i++) {                Log.i(TAG, "当前线程名:" + Thread.currentThread().getName());                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    }empty@Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        TestThread testThread=new TestThread();        Thread thread2=new Thread(testThread,"Thread2");        thread2.start();        //调用thread2 join()        try {            thread2.join();        } catch (InterruptedException e) {            e.printStackTrace();        }        //主线程每秒打印一次        for (int i = 0; i < 5; i++) {            Log.i(TAG, "当前线程名:" + Thread.currentThread().getName());            try {                Thread.sleep(1000);            } catch (InterruptedException e) {                e.printStackTrace();            }        }    }    private class TestThread implements Runnable{        @Override        public void run() {            for (int i = 0; i < 5; i++) {                Log.i(TAG, "当前线程名:" + Thread.currentThread().getName());                try {                    Thread.sleep(1000);                } catch (InterruptedException e) {                    e.printStackTrace();                }            }        }    }

未使用Thread2.join()运行日志如下,可以看到主线程和子线程交替运行


当前线程名:main
当前线程名:Thread2
当前线程名:main
当前线程名:Thread2
当前线程名:main
当前线程名:Thread2
当前线程名:main
当前线程名:Thread2
当前线程名:main
当前线程名:Thread2

在看下thread2使用join(),运行结果如何

当前线程名:Thread2
当前线程名:Thread2
当前线程名:Thread2
当前线程名:Thread2
当前线程名:Thread2
当前线程名:main
当前线程名:main
当前线程名:main
当前线程名:main
当前线程名:main

通过日志可以看到,只有等thread2运行完了,主线程才开始运行.在看看使用join2000)看下运行日志如何

08-17 13:43:47.584 31157-31231/com.threaddemo2 I/MainActivity: 当前线程名:Thread2
08-17 13:43:48.584 31157-31231/com.threaddemo2 I/MainActivity: 当前线程名:Thread2
08-17 13:43:49.584 31157-31157/com.threaddemo2 I/MainActivity: 当前线程名:main
08-17 13:43:49.585 31157-31231/com.threaddemo2 I/MainActivity: 当前线程名:Thread2
08-17 13:43:50.585 31157-31231/com.threaddemo2 I/MainActivity: 当前线程名:Thread2
08-17 13:43:50.585 31157-31157/com.threaddemo2 I/MainActivity: 当前线程名:main
08-17 13:43:51.585 31157-31157/com.threaddemo2 I/MainActivity: 当前线程名:main
08-17 13:43:51.585 31157-31231/com.threaddemo2 I/MainActivity: 当前线程名:Thread2
08-17 13:43:52.585 31157-31157/com.threaddemo2 I/MainActivity: 当前线程名:main
08-17 13:43:53.586 31157-31157/com.threaddemo2 I/MainActivity: 当前线程名:main

因为thread2是每秒打印一次日志,thread2.join2000)了2秒,所以打印2次后,Object对象锁释放了。其实这种现象很好解释,因为join()内部的同步方法更深层次调用的是lock.wait(long millis)方法。再来看看Object对象的wait(long millis),说的简单点就是mills毫秒后释放Object对象锁。(未完待续)