计算机可以将多种活动同时进行,这种思想放在Java中被称为并发,而将并发完成的每一件事情称为线程。
在Java中,并发机制非常重要。在以往的程序设计中,我们都是一个任务完成后再进行下一个任务,这样下一个任务的开始必须等待前一个任务的结束。Java语言提供了并发机制,程序员可以在程序中执行多个线程,每一个线程完成一个功能,并与其他线程并发执行,这种机制被称为多线程。
一个线程则是进程中的执行流程,一个进程中可以同时包括多个线程,每个线程也可以得到一小段程序的执行时间,这样一个进程就可以具有多个并发执行的线程。在单线程中,程序代码按调用顺序依次往下执行。如果需要一个进程同时完成多段代码的操作,就需要使用多线程。
通过java.lang.Thread
类的对象来代表线程
- 创建
MyThread
类,让其继承Thread
类并重写run()
方法。
public class MyThread0 extends Thread{
//必须重写run方法
//run方法描述线程的执行内容
@Override
public void run() {
for (int i = 0; i < 4; i++) {
System.out.println("子线程正在输出:" + i);
}
}
}
- 创建
MyThread
类的实例对象,即创建一个新线程。 - 调用
start()
方法,启动线程。
public class test {
//主线程和子线程执行是随机的
public static void main(String[] args) {
Thread t=new MyThread0();
//注意是调用start不是调用run
t.start();
for (int i = 0; i < 4; i++) {
System.out.println("主线程正在输出:" + i);
}
}
}
优点:编码简单
缺点:线程类已经继承了Thread,无法继承其他类,不利于功能的扩展
- 创建
MyRunnable
类实现Runnable
接口。Runnable
接口只有一个run
方法,源代码如下:
public interface Runnable {
public abstract void run();
}
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 4; i++) {
System.out.println("子线程1输出:" + i);
}
}
}
- 创建
MyRunnable
类的实例对象myRunnable
。 - 把实例对象
myRunnable
作为参数来创建Thread
类的实例对象thread
,实例对象thread
就是一个新线程。
调用start()
方法,启动线程。
一并演示三种简化方式:
public class test1 {
public static void main(String[] args) {
Runnable runnable = new MyRunnable();//多态
new Thread(runnable).start();
//简化形式1:匿名内部类
Runnable runnable1=new Runnable() {
@Override
public void run() {
for (int i = 0; i < 4; i++) {
System.out.println("子线程2输出:" + i);
}
}
};
new Thread(runnable1).start();
//简化形式2:匿名内部类(不创建变量)
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 4; i++) {
System.out.println("子线程3输出:" + i);
}
}
}).start();
//简化形式3:匿名内部类(lambda表达式)
new Thread(()-> {
for (int i = 0; i < 4; i++) {
System.out.println("子线程3输出:" + i);
}
}
).start();
for (int i = 0; i < 4; i++) {
System.out.println("主线程输出:" + i);
}
}
}
优点:任务类只是实现接口,可以继续继承其他类,实现其他接口,扩展性强。
缺点:需要多一个Runnable
对象。
Callable
接口只有一个call()
方法,源码如下:
public interface Callable<V> {
V call() throws Exception;
}
从源码我们可以看到Callable
接口和Runnable
接口类似,它们之间的区别在于run()
方法没有返回值,而call()
方法是有返回值的。
- 创建
MyCallable
类实现Callable
接口。
import java.util.concurrent.Callable;
//要使用泛型来指定返回的结果类型
public class MyCallable implements Callable<String> {
private int n;
public MyCallable(int n) {
this.n = n;
}
@Override
public String call() throws Exception {
int sum=0;
for (int i = 0; i < n; i++) {
sum+=i;
}
return "结果是:"+sum;
}
}
- 创建
MyCallable
类的实例对象myCallable
。 - 把实例对象
myCallable
作为参数来创建FutureTask
类的实例对象futureTask
。 - 把实例对象
futureTask
作为参数来创建Thread
类的实例对象thread
,实例对象thread
就是一个新线程。
调用start()
方法,启动线程。
public class test2 {
public static void main(String[] args) throws Exception {
// 创建一个Callable的对象
Callable<String> cl=new MyCallable(100);
// 把Callable的对象封装成一个FutureTask对象(任务对象)
// 未来任务对象的作用?
// 是一个任务对象,实现了Runnable对象.
// 可以在线程执行完毕之后,用未来任务对象调用get方法获取线程执行完毕后的结果。
FutureTask<String> ft=new FutureTask<>(cl);
// 把任务对象交给一个Thread对象
Thread t=new Thread(ft);
t.start();
// 获取线程执行完毕后返回的结果。
// 注意:如果执行到这儿,假如上面的线程还没有执行完毕
// 这里的代码会暂停,等待上面线程执行完毕后才会获取结果。
System.out.println(ft.get());
}
}
优点:任务类只是实现接口,可以继续继承其他类,实现其他接口,扩展性强。可以在线程执行完毕后获取线程执行的结果。
缺点:编码复杂
public class test3 {
public static void main(String[] args) {
Thread t1 = new MyThread("1号线程");
// t1.setName("1号线程");
t1.start();
System.out.println(t1.getName()); // Thread-0(默认)
Thread t2 = new MyThread("2号线程");
// t2.setName("2号线程");
t2.start();
System.out.println(t2.getName()); // Thread-1
// 主线程对象的名字
// 哪个线程执行它,它就会得到哪个线程对象。
Thread m = Thread.currentThread();//得到的是主线程的名字
m.setName("最牛的线程");
System.out.println(m.getName()); // main
for (int i = 1; i <= 5; i++) {
System.out.println(m.getName() + "线程输出:" + i);
}
}
}
输出结果如下:
原创文章,作者:速盾高防cdn,如若转载,请注明出处:https://www.sudun.com/ask/87662.html