多线程的常用方法大多都在 Thread 类中定义了。
多线程的运行状态是不确定的,如果想要获取到某一个特定的线程,就需要通过线程的名字来进行线程操作。所以线程的名称是一个很重要的概念,在 Thread 类中就提供有线程名称的方法。
public Thread(Runnable target, String name)
public final void setName(String name)
public final String getName()
线程名字不建议修改、重名。
所有的线程对象都要执行run()
,那么可以考虑获取当前线程,在 Thread 类中提供有此方法public static Thread currenThread()
class MyThread implements Runnable {
public void run() {
System.out.println(Thread.currentThread().getName());
}
}
public class Test {
public static void main(String[] args) throws Exception {
MyThread mt = new MyThread();
new Thread(mt, "线程A").start();
new Thread(mt, "线程B").start(); // 当设置了名字的时候就显示设置的名字
new Thread(mt).start(); // 无名字也能自动命名为一个不重复的名字
}
}
当直接通过线程对象执行run()
时:mt.run()
观察结果会发现此时线程名字为 main,所以得出结论,主方法也是一个线程。 每当使用 java 命令运行程序的时候就表示启动了一个 JVM 进程,一台电脑上只可以同时启动一个,所以每一个 JVM 进程都会有其各自的线程。在开发中,主线程可创建出若干的子线程,目的是可以将一些复杂逻辑交由子线程处理。
如果说现在希望某一个线程可以暂缓执行一次,那么就可以使用休眠处理。在 Thread 中定义的休眠方法:
public static void sleep(long millis) throws InterruptedException
public static void sleep(long millis, int nanos) throws InterruptedException
在进行休眠的时候有可能会产生中断异常,其为 Exception 的子类,所以必须进行处理。
public class Test {
public static void main(String[] args) throws Exception {
new Thread(
() -> {
for (int x = 0; x < 10; x++) {
System.out.println(Thread.currentThread().getName() + x);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},
"线程对象")
.start();
}
}
休眠的主要特点时可以自动实现线程的唤醒。但是需要注意到的是,如果有多个线程对象需要进行休眠处理,那么休眠的顺序也是有说法的。
public class Test {
public static void main(String[] args) throws Exception {
for (int i = 0; i < 5; i++) {
new Thread(
() -> {
for (int x = 0; x < 10; x++) {
System.out.println(Thread.currentThread().getName() + x);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
},
"线程对象" + i)
.start();
}
}
}
此时将产生五个线程对象。并且这五个对象执行的方法是一样的。从直觉上来查看结果:
线程对象00
线程对象40
线程对象30
线程对象10
线程对象20
线程对象01
线程对象31
线程对象11
线程对象41
线程对象21
线程对象12
线程对象42
线程对象02
线程对象32
线程对象22
线程对象13
线程对象33
线程对象23
线程对象03
线程对象43
线程对象04
线程对象24
线程对象14
线程对象34
线程对象44
线程对象15
线程对象05
线程对象25
线程对象45
线程对象35
线程对象46
线程对象36
线程对象16
线程对象06
线程对象26
线程对象07
线程对象47
线程对象17
线程对象37
线程对象27
线程对象38
线程对象18
线程对象08
线程对象48
线程对象28
线程对象19
线程对象49
线程对象39
线程对象09
线程对象29
会发现是一起执行休眠,一起执行唤醒。但实际上是有先后顺序的。
在线程的休眠我们发现提供有一个中断异常,实际上就证明线程的休眠是可以被打断的,这种打断是由其他线程完成的。在 Thread 里提供有两个相关的方法:
public boolean isInterrupted()
public void interrupt()
public class Test {
public static void main(String[] args) throws Exception {
Thread thread =
new Thread(
() -> {
try {
System.out.println("sleep");
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("done");
});
thread.start();
System.out.println("开始");
Thread.sleep(10000);
if (!thread.isInterrupted()) {
System.out.println("执行");
thread.interrupt();
}
}
}
当满足某些条件之后,某个线程对象可以一直独占资源,直到该线程的程序执行结束。
无强制执行时:
public class Test {
public static void main(String[] args) throws Exception {
Thread thread =
new Thread(
() -> {
for (int x = 0; x < 100; x++) {
System.out.println(Thread.currentThread().getName() + x);
}
},
"线程1 ");
thread.start();
for (int x = 0; x < 100; x++) {
System.out.println("主线程" + x);
}
}
}
两个线程交替执行,若想要主线程不断执行,则可用 Thread 中的强制执行方法:public final void join() throws InterruptedException
public class Test {
public static void main(String[] args) throws Exception {
Thread mainThread = Thread.currentThread();
Thread thread =
new Thread(
() -> {
for (int x = 0; x < 100; x++) {
if (x > 5) {
try {
mainThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName() + x);
}
},
"线程1 ");
thread.start();
for (int x = 0; x < 100; x++) {
System.out.println("主线程" + x);
}
}
}
先将资源让出去,让别的线程先执行。可以使用 Thread 中的public static void yield()
public class Test {
public static void main(String[] args) throws Exception {
Thread thread =
new Thread(
() -> {
for (int x = 0; x < 100; x++) {
if (x % 3 == 0) {
Thread.yield();
System.out.println("礼让");
}
System.out.println(Thread.currentThread().getName() + x);
}
},
"线程1 ");
thread.start();
for (int x = 0; x < 100; x++) {
// Thread.sleep(100);
System.out.println("主线程" + x);
}
}
}
礼让执行的时候只应用于一次当前的资源。
理论上来讲,线程的优先级越高越先执行。在 Thread 里提供有两个方法:
public final void setPriority(int newPriority)
public final int getPriority()
通过 int 类型的数字进行优先级定义。在 Thread 中定义有如下几个常量用来设置优先级:
public static final int MAX_PRIORITY = 10
public static final int NORM_PRIORITY = 5
public static final int MIN_PRIORITY = 1
例如:线程对象.setPriority(Thread.MAX_PRIORITY)
优先级高的是有可能限制性,并不是绝对性。
主方法是一个线程,其优先级为 5. 属于中等优先级。默认线程的优先级也是 5.