多线程
Java 提供了三种创建线程的方法:
- 通过实现 Runnable 接口
- 通过继承 Thread 类本身
- 通过 Callable 和 Future 创建线程
注意: Java中真正能创建新线程的只有Thread类对象
1. 通过实现 Runnable 接口
通过实现Runnable接口来实现多线程的步骤:
- 写一个实现Runnable接口的实现类RunnableDemo
- 在RunnableDemo类中实现Runnable接口的run()方法,里面写线程的执行体
- 创建RunnableDemo的实例R1
- 将RunnableDemo实例R1放入Thread实例中创建Thread实例t
- Thread实例t调用start()方法执行线程
class RunnableDemo implements Runnable {
private Thread t;
private String threadName;
RunnableDemo( String name) {
threadName = name;
System.out.println("Creating " + threadName );
}
public void run() {
System.out.println("Running " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
// 让线程睡眠一会
Thread.sleep(50);
}
}catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
// 参数:Runnable实例、线程名
t = new Thread (this, threadName);
t.start ();
}
}
}
public class TestThread {
public static void main(String args[]) {
RunnableDemo R1 = new RunnableDemo( "Thread-1");
R1.start(); // 执行线程
RunnableDemo R2 = new RunnableDemo( "Thread-2");
R2.start();
}
}
也可以通过匿名实现Runnable接口来实现线程:
// 1.匿名实现Runnable接口并重写run方法
public static void myRunable() {
Runnable runnable = new Runnable() {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread thread1 = new Thread(runnable, "Thread1");
Thread thread2 = new Thread(runnable, "Thread2");
thread1.start();
thread2.start();
}
2. 通过继承 Thread 类本身
通过继承Thread类来实现多线程的步骤:
- 写一个继承Thread类的子类ThreadDemo
- 在ThreadDemo类中重写run()方法,里面写线程的执行体
- 创建ThreadDemo的实例T1
- 将ThreadDemo实例T1放入Thread实例中创建Thread实例t
- Thread实例t调用start()方法执行线程
class ThreadDemo extends Thread {
private Thread t;
private String threadName;
ThreadDemo( String name) {
threadName = name;
System.out.println("Creating " + threadName );
}
public void run() {
System.out.println("Running " + threadName );
try {
for(int i = 4; i > 0; i--) {
System.out.println("Thread: " + threadName + ", " + i);
// 让线程睡眠一会
Thread.sleep(50);
}
}catch (InterruptedException e) {
System.out.println("Thread " + threadName + " interrupted.");
}
System.out.println("Thread " + threadName + " exiting.");
}
public void start () {
System.out.println("Starting " + threadName );
if (t == null) {
t = new Thread (this, threadName);
t.start ();
}
}
}
public class TestThread {
public static void main(String args[]) {
ThreadDemo T1 = new ThreadDemo( "Thread-1");
T1.start();
ThreadDemo T2 = new ThreadDemo( "Thread-2");
T2.start();
}
}
与第一种方式非常类似,也可通过匿名内部类来实现:
public static void myThread() {
Thread thread1 = new Thread("Thread1") {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread thread2 = new Thread("Thread2") {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
thread1.start();
thread2.start();
}
3. 通过 Callable 和 Future 创建线程
通过Callable和Future创建线程的步骤:
- 创建一个实现了Callable接口的实现类CallableThreadTest
- 实现call()方法,在里面写线程的执行体,并且具有返回值
- 创建CallableThreadTest类的实例ctt
- 用FutureTask包装该CallableThreadTest类的实例ctt, 该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值
- 使用 FutureTask 对象作为 Thread 对象 t 的 target 创建线程
- 调用Thread对象 t 的start()方法启动线程
- 调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值
public class CallableThreadTest implements Callable<Integer> {
public static void main(String[] args)
{
CallableThreadTest ctt = new CallableThreadTest();
FutureTask<Integer> ft = new FutureTask<>(ctt);
for(int i = 0;i < 100;i++)
{
System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i);
if(i==20)
{
Thread t = new Thread(ft,"有返回值的线程");
t.start();
}
}
try
{
System.out.println("子线程的返回值:"+ft.get());
} catch (InterruptedException e)
{
e.printStackTrace();
} catch (ExecutionException e)
{
e.printStackTrace();
}
}
@Override
public Integer call() throws Exception
{
int i = 0;
for(;i<100;i++)
{
System.out.println(Thread.currentThread().getName()+" "+i);
}
return i;
}
}
也可以通过匿名内部类来实现:
public static void myCallable() {
Callable<String> callable = new Callable<String>() {
@Override
public String call() throws Exception {
System.out.println(Thread.currentThread().getName());
Thread.sleep(1000);
return Thread.currentThread().getName();
}
};
FutureTask<String> futureTask = new FutureTask<>(callable);
// 多个Thread使用同一个FutureTask效果和一个Thread一样
new Thread(futureTask, "Thread").start();
try {
System.out.println("线程返回值:" + futureTask.get());
} catch (Exception e) {
e.printStackTrace();
}
}
4. Thread类的常用方法
(1) 实例方法
public void start()
:使该线程开始执行;Java 虚拟机调用该线程的 run 方法public void run()
:如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;否则,该方法不执行任何操作并返回public final void setName(String name)
:改变线程名称,使之与参数 name 相同public final void setPriority(int priority)
:更改线程的优先级public final void setDaemon(boolean on)
:将该线程标记为守护线程或用户线程public final void join(long millisec)
:等待该线程终止的时间最长为 millis 毫秒public void interrupt()
:中断线程public final boolean isAlive()
:测试线程是否处于活动状态
(2) 静态方法
public static void yield()
:暂停当前正在执行的线程对象,并执行其他线程public static void sleep(long millisec)
:在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响public static boolean holdsLock(Object x)
:当且仅当当前线程在指定的对象上保持监视器锁时,才返回 truepublic static Thread currentThread()
:返回对当前正在执行的线程对象的引用public static void dumpStack()
:将当前线程的堆栈跟踪打印至标准错误流
5. Future类的常用方法
上面用到的FutureTask是Future子类的实现类。
(1) 实例方法
get()
:若任务结束后返回结果,反之,则会阻塞线程,直到任务执行完毕get(long timeout, TimeUnit unit)
:最多再多等待给定的时间,就停止线程cancel(boolean mayInterruptIfRunning)
:用来停止一个任务,如果任务可以停止(通过mayInterruptIfRunning来进行判断),则可以返回true,如果任务已经完成或者已经停止,或者这个任务无法停止,则会返回falseisDone()
:判断当前方法是否完成isCancel()
:判断当前方法是否取消