Java多线程中我们有一些常用的操作线程的方法,如start(),sleep(),join(),yield(),wait(),notify()和interrupt()等方法。就是这些方法我们才能启动线程使线程完成我们想要完成的任务。我写过一篇创建线程的博客,其中就介绍了线程的三种状态:就绪状态,运行状态和阻塞状态。而以上一些方法的调用就是线程状态变化的原因之一。
1.有关线程名称的方法
我们首先来看看Thread类的一个构造方法:
public Thread(Runnable target, String name)
这个构造方法可以传入一个Runnable类型对象和String对象。我们知道传入的Runnable类型的对象实际上就是我们赋予这个线程的任务,而这个String对象实际上就是我们为这个线程赋予的名称。
我们来试一试:
public class NameTest1 {
public static void main(String[] args) {
Thread thread1 = new Thread(new Runnable() {
public void run() {
System.out.println("这是线程");
}
},"Thread-user1");
}
}
那么我们这个线程的名称到底是不是我们所赋的名称呢?我们就要用到查看线程的方法了。
public final String getName()
这个方法会返回调用这个方法的线程的线程名称。
我们使用这个方法来查看上面的的代码是否赋名成功:
public class NameTest1 {
public static void main(String[] args) {
Thread thread1 = new Thread(new Runnable() {
public void run() {
System.out.println("这是线程");
}
},"Thread-user1");
System.out.println("thread1线程的名称为:" + thread1.getName());
}
}
结果:
可以看到,我们的线程名称与我们所赋的名称是相同的。
那么如果我们想要更改一个线程的名称怎么办呢?就要用到这个方法:
public final synchronized void setName(String name)
这个方法会修改调用这个方法的线程的线程名称。
我们来试一试:
public class NameTest1 {
public static void main(String[] args) {
Thread thread1 = new Thread(new Runnable() {
public void run() {
System.out.println("这是线程");
}
},"Thread-user1");
System.out.println("thread1线程的名称为:" + thread1.getName());
thread1.setName("Thread-newName");
System.out.println("thread1线程的名称为:" + thread1.getName());
}
}
结果:
2.sleep()方法
public static native void sleep(long millis)
这个方法Thread类的静态方法,需要传入一个long型数据(millis表示单位为毫秒)。这个方法会使调用它的线程(调用这个方法所在的线程)休眠,休眠时间为传入的参数大小乘以1毫秒。
!!!注意:线程使用这个方法进入休眠时会释放CPU资源,但不会释放锁。
我们来使用一下这个方法:
public class SleepTest {
public static void main(String[] args) throws InterruptedException {
Runnable runnable = new Runnable() {
private volatile int i = 0;
public void run() {
for(;;){
Thread thread = Thread.currentThread();
synchronized (this){
i++;
if(i<6){
System.out.println(thread.getName() + "线程。。。" + i);
}else {
while(true){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}
};
Thread thread1 = new Thread(runnable,"Thread-test1");
Thread thread2 = new Thread(runnable,"Thread-test2");
thread1.start();
thread2.start();
}
}
结果如图:
可以看到,此时程序无法结束,这是因为线程1休眠无法终止。而线程1休眠后,线程2却仍然不能执行被同步的代码块。
2.yield()方法
public static native void yield()
这个方法是Thread类的静态方法,这个方法会暂停调用这个方法的线程(调用这个方法所在的线程),释放CPU资源,但不会释放锁。看起来这个方法和Sleep有些相似,但是它们也有区别:1.这个方法暂停时间是没法控制的;2.暂停结束后直接进入就绪态,不会造成阻塞;3.线程因这个方法释放的CPU资源只能被与线程同优先级的线程获得。
不使用这个方法:
public class YieldTest {
public static void main(String[] args) {
Runnable runnable = new Runnable() {
public void run() {
for(int i=0; i<5; i++){
// Thread.yield();
System.out.println(Thread.currentThread().getName() + "线程打印的: i = " + i);
}
}
};
new Thread(runnable,"Thread-test1").start();
new Thread(runnable,"Thread-test2").start();
new Thread(runnable,"Thread-test3").start();
}
}
结果:
去掉注释后,使用了yield()方法后的结果:
我们可以看到使用了yield()方法后的打印是无规律的。
3.join()方法
public final void join()
该方法会使所在线程休眠,直到调用该方法的线程执行完毕之后再开始执行所在线程。
不使用该方法:
public class JoinTest {
public static void main(String[] args) throws InterruptedException {
Runnable runnable = new Runnable() {
public void run() {
String name = Thread.currentThread().getName();
synchronized (this){
Thread.yield();
System.out.println(name + "执行");
}
}
};
Thread thread1 = new Thread(runnable,"Thread-test1");
Thread thread2 = new Thread(runnable,"Thread-test2");
Thread thread3 = new Thread(runnable,"Thread-test3");
Thread thread4 = new Thread(runnable,"Thread-test4");
Thread thread5 = new Thread(runnable,"Thread-test5");
thread1.start();
// thread1.join();
thread2.start();
// thread2.join();
thread3.start();
// thread3.join();
thread4.start();
// thread4.join();
thread5.start();
// thread5.join();
}
}
不使用该方法的结果:
使用该方法的结果:
4.interrupt()方法
public void interrupt()
该方法会将线程的中断标志位修改为true。当中断标志位为true后,如果线程未受阻塞,那么就只是中断标志位变为true;若是线程处于阻塞状态,此时受阻线程会抛出一个异常以退出阻塞状态,同时中断标志位变回false。
使用这个方法:
public class InterruptTest {
public static void main(String[] args) throws InterruptedException {
Runnable runnable = new Runnable() {
public void run() {
while(true){
boolean bool = Thread.currentThread().isInterrupted();
System.out.println(Thread.currentThread().getName() + "线程是否中断:" + bool);
if(bool){
System.out.println(Thread.currentThread().getName() + "线程阻塞");
return;
}
}
}
};
Thread thread = new Thread(runnable, "Thread-test");
thread.start();
Thread.sleep(2);
thread.interrupt();
}
}
结果:
!!!注意:interrupt()方法只是修改了中断标志位,实际上不会中断线程
请看如下代码:
public class InterruptTest {
public static void main(String[] args) throws InterruptedException {
Runnable runnable = new Runnable() {
public void run() {
while(true){
boolean bool = Thread.currentThread().isInterrupted();
System.out.println(Thread.currentThread().getName() + "线程是否中断:" + bool);
// if(bool){
// System.out.println(Thread.currentThread().getName() + "线程阻塞");
// return;
// }
}
}
};
Thread thread = new Thread(runnable, "Thread-test");
thread.start();
Thread.sleep(2);
thread.interrupt();
}
}
结果:
可以看到此时中断标志位为true,但是线程却并没有中断。
5.wait()方法和notify()方法
这两个方法相对于其它方法有一些特殊,而且这两个方法一般都是成对使用,所以我把他们放在一起。
public final void wait()
该方法是Object类的成员方法,调用该方法会使线程在wait()方法的代码处停止,线程被置入“预执行队列”中,等待通知或中断,同时线程释放锁。
!!注意:wait()方法必须在同步方法或同步代码块中使用。
public final native void notify()
该方法是Object类的成员方法,调用该方法后将会在调用该方法的对象的“预执行队列”中随机挑出一个线程进行通知。该方法一般与wait()方法成对使用。还有notifyAll()方法,则会将调用该方法的对象的“预执行队列”中所以线程进行通知。
!!注意:notify()方法必须在同步方法或同步代码块中使用,而且其与wait()方法成对使用时,锁的对象必须是同一对象。
如下代码:
public class WaitAndNotifyTest {
public static void main(String[] args) throws InterruptedException {
Runnable runnable = new Runnable() {
public void run() {
for(int i=0; i<10; i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(i == 2){
System.out.println(Thread.currentThread().getName() + "调用wait方法,开始等待");
try {
synchronized (this){
this.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + "线程打印:i = " + i);
}
}
};
Thread thread1 = new Thread(runnable,"Thread-test");
thread1.start();
Thread.sleep(5000);
synchronized (runnable){
System.out.println("通知" + thread1.getName() + "线程");
runnable.notify();
}
}
}
结果:
我的所有演示代码都上传在github,链接:https://github.com/nodonotnodo/JavaSE-csdn