三·多线程的常用操作方法
3.1 线程的命名于取得命名
多线程的运行状态是不确定的,所以对于多线程操作必须有一个明确标识出线程对象的信息,这个信息往往通过名称来描述。在Thread类中提供有如下的线程名称方法:
要想取得线程的对象,在Thread类中提供有一个方法取得当前线程对象:
/**
* Returns a reference to the currently executing thread object.
*
* @return the currently executing thread.
*/
public static native Thread currentThread();
下面请观察线程名取得的方法和设置线程方法名:
package com.revision.Thread;
public class SettingName implements Runnable {
@Override
public void run() {
for(int i = 0; i <= 10; i++){
System.out.println("当前线程为:" + Thread.currentThread().getName()
+ " i = " + i);
}
}
public static void main(String[] args) {
SettingName sn = new SettingName();
new Thread(sn).start();
new Thread(sn).start();
new Thread(sn,"name").start();
}
}
运行结果为:
通过使用currentThread()方法 获取当前 线程 让后使用getName()方法获取正在运行的方法名。
可以发现,未设置名字的线程默认叫做 Thread-0和Thread-1 而设置过名字的线程 name 显示了设置过的名字
需要注意的是,线程名字如果要设置请避免重复,同时中间不要修改。
观察以下代码
class MyThread implements Runnable {
@Override
public void run() {
System.out.println("当前线程:" + Thread.currentThread().getName());
}
}
public class TestDemo {
public static void main(String[] args) {
MyThread mt = new MyThread();
mt.run(); // 直接通过对象调用run()方法
new Thread(mt).start(); // 通过线程调用
}
}
通过以上程序我们发现,主方法本身就是一个线程,所有的线程都是通过主线程创建并启动的。
疑问:进程在哪?
实际上每当使用了java命令去解释程序的时候,都表示启动了一个新的JVM进程。而主方法只是这个进程上的一个线程而已。
3.2 线程休眠(sleep方法)
线程休眠:指的是让线程暂缓执行一下,等到了预计时间之后再恢复执行。
线程休眠会交出CPU,让CPU去执行其他的任务。但是有一点要非常注意,sleep方法不会释放锁,也就是说如果当前线程持有对某个对象的锁,则即使调用sleep方法,其他线程也无法访问这个对象.
让我们看看sleep()方法:
public static native void sleep(long millis) throws InterruptedException
休眠时间 用的是 毫秒 为单位
代码示例:
package com.revision.Thread;
public class TestSleep implements Runnable {
@Override
public void run() {
for(int i = 0; i <= 10;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("当前线程:" + Thread.currentThread().getName() + " i = " + i);
}
}
public static void main(String[] args) {
TestSleep ts = new TestSleep();
new Thread(ts).start();
new Thread(ts).start();
new Thread(ts).start();
}
}
运行结果:
结果是:每1s有三个线程执行。
通过代码观察会错误的认为这三个线程是同时休眠的,但是千万要记住,所有的代码是依次进入到run()方法中的。
真正进入到方法的对象可能是多个,也可能是一个。进入代码的顺序可能有差异,但是总体的执行是并发执行。
3.3 线程让步(yield()方法)
暂停当前正在执行的线程对象,并执行其他线程。
意思就是调用yield方法会让当前线程交出CPU权限,让CPU去执行其他的线程。它跟sleep方法类似,同样不会释放锁。但是yield不能控制具体的交出CPU的时间,另外,yield方法只能让拥有相同优先级的线程有获取CPU执行时间的机会。
注意,调用yield方法并不会让线程进入阻塞状态,而是让线程重回就绪状态,它只需要等待重新获取CPU执行时间,这一点是和sleep方法不一样的。
sleep是线程睡眠到期自动苏醒,并返回到可运行状态(就绪),不是运行状态。
代码示例:
class MyThread implements Runnable {
@Override
public void run() {
for (int i = 0; i < 3 ; i++) {
Thread.yield();
System.out.println("当前线程:" + Thread.currentThread().getName()+" ,i = "
+i);
}
}
}
public class Test {
public static void main(String[] args){
MyThread mt = new MyThread();
new Thread(mt).start();
new Thread(mt).start();
new Thread(mt).start();
}
}
3.4 join()方法
**等待该线程终止。**意思就是如果在主线程中调用该方法时就会让主线程休眠,让调用该方法的线程run方法先执行完毕之后在开始执行主线程。
示例:
package com.revision.Thread;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
class MyJoin implements Runnable{
@Override
public void run() {
try {
System.out.println("主线程睡眠前的时间:");
TestJoin.printTime();
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName());
System.out.println("睡眠结束的时间:");
TestJoin.printTime();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class TestJoin {
public static void main(String[] args) throws InterruptedException {
MyJoin mj = new MyJoin();
Thread thread = new Thread(mj,"子线程A");
thread.start();
System.out.println(Thread.currentThread().getName());
thread.join();
System.out.println("代码结束!");
}
public static void printTime(){
Date date = new Date();
DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String time = format.format(date);
System.out.println(time);
}
}
运行结果为
也就是 先获取了主线程的名字,然后调用该方法的线程A开始运行,等到线程A运行完了 随后继续运行主线程。