java Thread的探索(一)

一、总结一下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 more
08-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: 当前线程名:thread1
08-17 11:31:22.238 25594-25664/threaddemo2 I/MainActivity: 当前线程名:thread1
08-17 11:31:22.239 25594-25665/threaddemo2 I/MainActivity: 线程暂停前状态:false
08-17 11:31:22.239 25594-25665/threaddemo2 I/MainActivity: 线程暂停后状态:true
08-17 11:31:22.239 25594-25664/threaddemo2 W/System.err: java.lang.InterruptedException
08-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: 当前线程名:thread1
08-17 11:31:23.241 25594-25664/threaddemo2 I/MainActivity: 当前线程名:thread1
08-17 11:31:24.242 25594-25664/threaddemo2 I/MainActivity: 当前线程名:thread1
08-17 11:31:25.242 25594-25664/threaddemo2 I/MainActivity: 当前线程名:thread1
08-17 11:31:26.242 25594-25664/threaddemo2 I/MainActivity: 当前线程名:thread1
08-17 11:31:27.242 25594-25664/threaddemo2 I/MainActivity: 当前线程名:thread1
08-17 11:31:28.243 25594-25664/threaddemo2 I/MainActivity: 当前线程名:thread1

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

empty
public 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对象锁。(未完待续)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值