Java 支持多线程开发。在进行并发访问处理时可得到更高的处理性能。
java.lang.Thread
类为实现多线程类的父类,但并不是实现了这个类就能够实现多线程处理。因为还需要覆写Thread类中public void run()
。
class MyThread extends Thread {
public String title;
public MyThread(String title) {
this.title = title;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(this.title + ", i =" + i);
}
}
}
多线程要执行的方法都应该在run()
中表明,但是run()
是不能被直接调用的,要启动多线程必须使用start()
.
假如主函数如此定义:
public class Test {
public static void main(String[] args) {
new MyThread("A").run();
new MyThread("B").run();
new MyThread("C").run();
}
}
结果:
A, i =0
A, i =1
A, i =2
A, i =3
A, i =4
A, i =5
A, i =6
A, i =7
A, i =8
A, i =9
B, i =0
B, i =1
B, i =2
B, i =3
B, i =4
B, i =5
B, i =6
B, i =7
B, i =8
B, i =9
C, i =0
C, i =1
C, i =2
C, i =3
C, i =4
C, i =5
C, i =6
C, i =7
C, i =8
C, i =9
使用start()
时:
public class Test {
public static void main(String[] args) {
new MyThread("A").start();
new MyThread("B").start();
new MyThread("C").start();
}
}
结果:
C, i =0
C, i =1
B, i =0
A, i =0
B, i =1
C, i =2
B, i =2
A, i =1
B, i =3
C, i =3
B, i =4
A, i =2
B, i =5
C, i =4
B, i =6
A, i =3
B, i =7
C, i =5
B, i =8
A, i =4
B, i =9
C, i =6
A, i =5
C, i =7
A, i =6
C, i =8
A, i =7
A, i =8
A, i =9
C, i =9
此时,多线程才启动。每一个线程对象只允许启动一次。
观察源码:
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
private native void start0();
其中的start0()
使用了JNI技术(Java Native Interface), 但是Java开发过程之中并不推荐这样使用。Thread类所提供的start0()
就表示此方法依赖于不同的操作系统来实现。
继承Thread受限于单继承,因此有第二种形式提供多线程实现:java.lang.Runnable
接口,此接口是一个函数式接口,只有一个run()
,因此可以使用lambda表达式操作。
实现此接口时,由于不再继承Thread,那么实现的类也就没有start()
, 如果不使用start()
无法进行多线程启动。
在Thread构造方法:public Thread(Runnable target)
中接收了此接口。
class MyThread implements Runnable {
public String title;
public MyThread(String title) {
this.title = title;
}
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(this.title + ", i =" + i);
}
}
}
public class Test {
public static void main(String[] args) {
Thread threadA = new Thread(new MyThread("A"));
threadA.start(); // 启动多线程
Thread threadB = new Thread(new MyThread("B"));
threadB.start(); // 启动多线程
Thread threadC = new Thread(new MyThread("C"));
threadC.start(); // 启动多线程
}
}
也可以利用lambda表达式进行定义:
public class Test {
public static void main(String[] args) {
for (int x = 0; x < 3; x++) {
String title = String.valueOf(x);
Runnable run =
() -> {
for (int i = 0; i < 10; i++) {
System.out.println(title + ", i =" + i);
}
};
new Thread(run).start();
}
}
}
简化版
public class Test {
public static void main(String[] args) {
for (int x = 0; x < 3; x++) {
String title = String.valueOf(x);
new Thread(
() -> {
for (int i = 0; i < 10; i++) {
System.out.println(title + ", i =" + i);
}
})
.start();
}
}
}
多线程的本质是在于多个线程可以进行统一资源的抢占
class MyThread implements Runnable {
private int ticket = 5;
@Override
public void run() {
for (int x = 0; x < 100; x++) {
if (this.ticket >= 0) {
System.out.println("卖票,票数 = " + this.ticket--);
}
}
}
}
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(); // 第三个线程启动
}
}
分析本程序执行结构:
Runnable接口有一个缺点,就是无法获取返回值。从 JDK 1.5 之后就提出了一个新的线程实现接口:java.util.concurrent.Callable
( JUC )
@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
class MyThread implements Callable<String> {
public String call() throws Exception {
for (int x = 0; x < 10; x++) {
System.out.println("线程执行x = " + x);
}
return "执行完毕";
}
}
public class Test {
public static void main(String[] args) throws Exception {
FutureTask<String> task = new FutureTask<>(new MyThread());
new Thread(task).start();
System.out.println("线程返回数据" + task.get());
}
}
run()
没有返回值。call()
,有返回值。多线程开发过程:定义线程主体类,实现接口,通过 Thread 对象,调用主体对象。并不意味调用了start()
线程就会运行,因为线程有一套自己的运行状态。
start()
启动,启动之后进入就绪状态,并没有马上执行。run()
。但不能一直执行,中间需要产生一些暂停的状态,例如:某些线程执行一段之间之后就需要让出资源。而后就进入到阻塞状态,当阻塞接触之后则回到就绪。run()
执行完毕之后,该线程的主要任务就执行结束,进入到停止状态。