一、总结一下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)内部是一个synchronized(lock){},而lock是Object对象,这就意味着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运行完了,主线程才开始运行.在看看使用join(2000)看下运行日志如何
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.join(2000)了2秒,所以打印2次后,Object对象锁释放了。其实这种现象很好解释,因为join()内部的同步方法更深层次调用的是lock.wait(long millis)方法。再来看看Object对象的wait(long millis),说的简单点就是mills毫秒后释放Object对象锁。(未完待续)