方式一:继承Thread类
1 //1、定义MyThread类继承自Thread类 2 public class MyThread extends Thread{ 3 //2、重写run方法:定义线程以后要干啥 4 @Override 5 public void run() { 6 for (int i = 0; i < 5; i++) { 7 System.out.println("子线程执行输出:" + i); 8 } 9 } 10 }
1 //多线程的创建方式一 : 继承Thread类 2 public class ThreadDemo1 { 3 public static void main(String[] args) { 4 //3、创建一个新的线程对象 5 Thread myThread = new MyThread(); //多态写法 6 //4、(注意点一)调用start方法启动线程(最终执行的还是run方法) 【子线程执行】 7 //调用start方法的原因:如果写为 myThread.run()就会当成普通类调用了run方法,那么将会是永远都是子线程先跑【效果同单线程一样】 8 myThread.start(); 9 10 //启动主线程 11 //(注意点二)主线程的位置不要写在子线程之前,不然会导致:子线程还没创建,先执行主线程【效果同单线程一样】 12 for (int i = 0; i < 5; i++) { 13 System.out.println("主线程启动:" + i); 14 } 15 } 16 }
方式二:实现Runnable接口
1 //1、定义MyRunnable类实现Runnable接口 2 public class MyRunnable implements Runnable{ 3 //2、重写run方法:定义线程的执行任务 4 @Override 5 public void run() { 6 for (int i = 0; i < 10; i++) { 7 System.out.println("子线程启动:" + i); 8 } 9 } 10 }
1 //多线程创建方式二 : 实现Runnable接口 2 public class RunnableDemo1 { 3 public static void main(String[] args) { 4 //3、创建任务对象【非线程对象】 5 Runnable target = new MyRunnable(); //多态 6 //4、把任务对象交给Thread处理 7 Thread thread = new Thread(target); 8 thread.start(); 9 10 //给主线程任务 11 for (int i = 0; i < 10; i++) { 12 System.out.println("主线程执行输出:" + i); 13 } 14 } 15 }
方式二的另一种实现方式:实现Runnable接口(匿名内部类的形式)
1 //线程的创建方式二:实现Runnable接口(匿名内部类的形式) 2 public class RunnableDemo2 { 3 public static void main(String[] args) { 4 //1、创建线程对象 5 Runnable target = new Runnable() { 6 //2、重写run方法 7 @Override 8 public void run() { 9 for (int i = 0; i < 10; i++) { 10 System.out.println("子线程1启动:" + i); 11 } 12 } 13 }; 14 15 //第一层简化 16 Thread thread2 = new Thread(new Runnable() { 17 @Override 18 public void run() { 19 for (int i = 0; i < 10; i++) { 20 System.out.println("子线程2启动:" + i); 21 } 22 } 23 }); 24 thread2.start(); 25 26 //第二层简化【Lambda表达式】 27 Thread thread3 = new Thread(() ->{ 28 for (int i = 0; i < 10; i++) { 29 System.out.println("子线程3启动:" + i); 30 } 31 }); 32 thread3.start(); 33 34 //3、把线程任务对象交给Thread处理 35 Thread thread = new Thread(target); 36 thread.start(); 37 for (int i = 0; i < 10; i++) { 38 System.out.println("主线程启动输出:" + i); 39 } 40 } 41 }
(由于有30条输出语句,在此只列举出部分结果)
1 import java.util.concurrent.Callable; 2 3 //1、定义任务类,实现Collable接口<泛型接口>,用于指定线程任务对象执行结果的返回值类型 4 public class MyCallable implements Callable<String> { 5 private int n; 6 7 public MyCallable(int n) { 8 this.n = n; 9 } 10 11 //2、重写run方法(线程的任务方法)【eg:计算1~n的和】 12 @Override 13 public String call() throws Exception { 14 int sum = 0; 15 //前n项和通项公式 16 sum = n * (1 + n) / 2; 17 return sum + ""; 18 } 19 }
1 import java.util.concurrent.Callable; 2 import java.util.concurrent.FutureTask; 3 4 //线程的创建方式三:实现Collable接口,结合FutureTask完成 5 public class CallableDemo { 6 public static void main(String[] args) { 7 //3、创建Callable任务对象 8 Callable<String> callable = new MyCallable(100); 9 //4、把Cabbable对象交给FutureTask 10 //FutureTask的作用1:使Runnable对象(实现了Runnable接口),交给Thread了 11 //FutureTask的作用2:可以在线程执行完毕之后调用get方法,得到线程的执行结果 12 FutureTask<String> futureTask = new FutureTask<>(callable); 13 //5、交给Thread线程处理 14 Thread thread = new Thread(futureTask); 15 //6、启动线程 16 thread.start(); 17 18 //线程2 19 Callable<String> callable2 = new MyCallable(200); 20 FutureTask<String> futureTask2 = new FutureTask<>(callable2); 21 Thread thread2 = new Thread(futureTask2); 22 thread2.start(); 23 24 try { 25 //此处的代码实在任务futureTask没有执行完毕才执行 26 String str1 = futureTask.get(); 27 System.out.println(str1); 28 }catch (Exception e){ 29 e.printStackTrace(); 30 } 31 32 try { 33 //同理:此处的代码实在任务futureTask2没有执行完毕才执行 34 String str2 = futureTask2.get(); 35 System.out.println(str2); 36 }catch (Exception e){ 37 e.printStackTrace(); 38 } 39 } 40 }
1 public class MyThread extends Thread{ 2 public MyThread() { 3 } 4 5 public MyThread(String name) { 6 super(name); 7 } 8 9 @Override 10 public void run() { 11 for (int i = 0; i < 5; i++) { 12 //System.out.println(this.getName() + "执行输出:" + i); 13 System.out.println(Thread.currentThread().getName() + "执行输出:" + i); 14 } 15 } 16 }
1 public class ThreadDemo1 { 2 public static void main(String[] args) { 3 Thread thread = new MyThread("1号"); 4 //thread.setName("1号"); 5 thread.start(); 6 System.out.println(thread.getName()); 7 8 Thread thread2 = new MyThread("2号"); 9 //thread2.setName("2号"); 10 thread2.start(); 11 System.out.println(thread2.getName()); 12 13 //那个线程执行它,它就拿到那个线程对象 14 //主线程的名称就叫main 15 Thread ct = Thread.currentThread(); 16 ct.setName("主线程"); 17 System.out.println(ct.getName()); 18 19 for (int i = 0; i < 5; i++) { 20 System.out.println(ct.getName() + "线程启动:" + i); 21 } 22 } 23 }
问题:两个线程都去取钱10W,银行亏钱10W。
分析:
1 public class Account { 2 private String cardId; 3 private double money; 4 5 public Account() { 6 } 7 8 public void drawMoney(double money){ 9 String threadName = Thread.currentThread().getName(); 10 if (this.money >= money){ 11 System.out.println(threadName + "来取钱,取出:" + money); 12 //更新余额 13 this.money -= money; 14 System.out.println("账户:" + this.cardId + "余额" + this.money); 15 }else { 16 System.out.println(threadName + "来取钱,余额不足"); 17 } 18 } 19 20 public Account(String cardId, double money) { 21 this.cardId = cardId; 22 this.money = money; 23 } 24 25 public String getCardId() { 26 return cardId; 27 } 28 29 public void setCardId(String cardId) { 30 this.cardId = cardId; 31 } 32 33 public double getMoney() { 34 return money; 35 } 36 37 public void setMoney(double money) { 38 this.money = money; 39 } 40 }
1 //取钱线程类 2 public class DrawThread extends Thread{ 3 //定义账户对象 4 private Account account; 5 public DrawThread(Account account,String name){ 6 super(name); 7 this.account = account; 8 } 9 @Override 10 public void run() { 11 //取钱 12 account.drawMoney(100000); 13 } 14 }
1 //模拟取钱案例 2 public class ThreadDemo { 3 public static void main(String[] args) { 4 //1、定义线程类,定义一个账户对象 5 Account account = new Account("3539687420",100000); 6 7 new DrawThread(account,"小明").start(); 8 new DrawThread(account,"小红").start(); 9 } 10 }
这就是线程安全问题:即多个线程先后依次访问共享资源可能造成的问题。
再看运行结果: