01 线程创建
- 继承Tread类
这里在每个控制台输出语句之后,增加sleep()函数,可以更明显得看出线程间“交替执行”或者说“并行执行”的效果。
public class MyFirstThread extends Thread{
@Override
public void run(){
for (int i = 0; i <10; i++) {
System.out.println("我是副线程"+i);
//加入sleep让交替运行更“明显”
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//主线程
public static void main(String[] args) {
//副线程创建和开启
MyFirstThread thread1=new MyFirstThread();
thread1.start();
for (int i = 0; i < 10; i++) {
System.out.println("我是主线程"+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
- 实现Runnable接口
此方法和继承Thread类方法相似,区别之在于:
- 声明时实现runnable接口而不是继承Thread类
- 开启线程需要扔到一个new Tread中
public class MyThread2 implements Runnable{
@Override
public void run() {
for (int i = 0; i <10; i++) {
System.out.println("我是副线程"+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
//创建副线程对象
MyThread2 thread=new MyThread2();
//开启线程
new Thread(thread).start();
for (int i = 0; i < 10; i++) {
System.out.println("我是主线程"+i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
- 实现Callable接口
- 可以定义返回值
- 可以抛出异常
- 在实现方式上比较复杂
import java.util.concurrent.*;
//1.实现Callable接口(可用“<>”规定返回类型,此处以Integ为例,
// 也可以不写,那么call方法返回类型应为“Object”)
public class MyThread5 implements Callable<Integer> {
//2.重写call方法, 注意返回类型应该与声明时的类型相同。↑
@Override
public Integer call(){
return 1;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyThread5 t1=new MyThread5();
MyThread5 t2=new MyThread5();
MyThread5 t3=new MyThread5();
//创建执行服务:
ExecutorService service = Executors.newFixedThreadPool(3);
//提交执行
Future<Integer> r1=service.submit(t1);
Future<Integer> r2=service.submit(t2);
Future<Integer> r3=service.submit(t3);
//获取结果
int re1=r1.get();
int re2=r2.get();
int re3=r3.get();
//关闭服务 施放资源
service.shutdown();
}
}
02 多个线程操作同一个对象
//多个线程操作一个对象
public class MyThread3 implements Runnable{
private int ticketNumbers =10;
@Override
public void run(){
while (true){
if(ticketNumbers<=0){
break;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"拿到了第"+ticketNumbers--+"张票");
}
}
public static void main(String[] args) {
MyThread3 t=new MyThread3();
new Thread(t,"小明").start();
new Thread(t,"小红").start();
new Thread(t,"小刚").start();
}
}
运行结果中,第四张票被重复“买”了三次。可以看出,在多个线程同时操作同一个对象时,会出现“Double Spending Attack”,在这种场景下应该加上类似数据库中的“锁”,避免多个线程在同一时间操作同一个对象。