二、线程的实现
(1)线程创建:共有三种方法
1. 继承Thread类
- 自定义线程类继承Thread类
- 重写run()方法,编写线程执行体
- 创建编程对象,调用start()方法启动线程
public class TestThread extends Thread{
@Override
public void run() {
//run方法线程体
for (int i = 0; i < 20; i++){
System.out.println("代码--"+i);
}
}
public static void main(String[] args) {
//main主线程
//创建一个线程对象
TestThread testThread = new TestThread();
//调用start方法开启线程
testThread.start();
for (int i = 0; i < 20; i++){
System.out.println("我在学习多线程--"+i);
}
}
}
需要注意的是:线程开启后不一定立刻执行,由cpu进行调度。
2. 实现Runnable接口
- 定义MyRunnable类实现Runnable接口
- 实现run()方法,编写线程执行体
- 创建线程对象,调用start()方法启动线程
package t2;
import t1.TestThread;
public class TestThread3 implements Runnable{
@Override
public void run() {
for (int i = 0; i < 200; i++){
System.out.println("我在看代码--"+i);
}
}
public static void main(String[] args) {
//创建runnable接口的实现类对象(一份资源)
TestThread3 testThread3 = new TestThread3();
//创建线程对象,通过线程对象来开启线程(多个代理)
Thread thread1 = new Thread(testThread3,"线程1");
Thread thread2 = new Thread(testThread3,"线程2");
Thread thread3 = new Thread(testThread3,"线程3");
thread1.start();
thread2.start();
thread3.start();
for (int i = 0; i <200; i++)
{
System.out.println("我在学习--"+i);
}
}
}
推荐使用第二种实现Runnable接口的方法,避免了单继承的局限性,灵活方便,方便同一个对象被多个线程使用。使用继承Thread方法的话,每一个线程都要单独继承Thread类,重写里面的run()方法,会造成代码冗余的后果。
public class TestThread4 implements Runnable{
private int ticketNum = 10;
@Override
public void run() {
while (true){
if (ticketNum <= 0){
break;
}
//模拟延时
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"-->拿到了第"+ticketNum--+"票");
}
}
public static void main(String[] args) {
//创建runnable接口的实现类对象(一份资源)
TestThread4 testThread3 = new TestThread4();
//创建线程对象,通过线程对象来开启线程(多个代理)
Thread thread1 = new Thread(testThread3,"线程1");
Thread thread2 = new Thread(testThread3,"线程2");
Thread thread3 = new Thread(testThread3,"线程3");
thread1.start();
thread2.start();
thread3.start();
}
}
运行结果如下:
从中可以发现,第七票被拿了两次,还出现了第0票,这些现象称为数据紊乱。
发现问题:多个线程操作同一个资源的情况下,线程不安全,数据紊乱。(需要线程同步的帮忙)
3. 实现Callable接口(Runnable是执行工作的独立任务,但是不返回任何值。如果我们希望任务完成之后有返回值,可以实现Callable接口。)
- 实现Callable接口,需要返回值类型
- 重写call()方法,需要抛出异常
- 创建目标对象
- 创建执行服务:ExecutorService ser = Executors.newFixedThreadPool(1);
- 提交执行:Future result1 = ser.submit(t1);
- 获取结果:boolean r1 = result1.get();
- 关闭服务:ser.shutdownNow();
import java.util.concurrent.*;
/**
* callable的好处:
* 1、可以定义返回值
* 2、可以抛出异常
*/
public class TestThread5 implements Callable<Boolean> {
@Override
public Boolean call() throws Exception {
int i = 0;
while (i < 100){
i ++;
}
System.out.println(Thread.currentThread().getName()+"完成了计数");
return true;
}
private int ticketNum = 10;
public static void main(String[] args) throws ExecutionException, InterruptedException {
TestThread5 testThread1 = new TestThread5();
TestThread5 testThread2 = new TestThread5();
TestThread5 testThread3 = new TestThread5();
//创建执行服务:
ExecutorService ser = Executors.newFixedThreadPool(3);
//提交执行
Future<Boolean> result1 = ser.submit(testThread1);
Future<Boolean> result2 = ser.submit(testThread2);
Future<Boolean> result3 = ser.submit(testThread3);
//获取结果
boolean r1 = result1.get();
boolean r2 = result2.get();
boolean r3 = result3.get();
//停止服务
ser.shutdownNow();
}
}