Java教程

Java --> 多线程1(线程3种创建方式、常用方法、线程安全、线程同步)

本文主要是介绍Java --> 多线程1(线程3种创建方式、常用方法、线程安全、线程同步),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

 

  • 多线程的三种创建方式:
  1. 继承Thread类;
  2. 实现Runnab接口;
  3. JDK5.0新增:实现Callable接口

方式一:继承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条输出语句,在此只列举出部分结果)

  • 方式三:JDK5.0新增:实现Callable接口
 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 }

  •  Thread类的常用方法:
 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 }

 

  •  Thread类的线程休眠方法

 

  •  线程安全问题:取钱模型演示
  • 需求:小明和小红使一对夫妻,它们有一个共同的账户,余额是10W元;
  • 如果小明和小红同时来取钱,而且2人都要取钱10W元,可能出现什么问题?

问题:两个线程都去取钱10W,银行亏钱10W。

 分析:

  1. 提供一个账户类,创建一个账户对象代表2个人的共享账户;
  2. 定义一个线程类,线程类可以处理账户对象;
  3. 创建2个线程对象,传入同一个账户对象;
  4. 启动2个线程,去同一个账户对象中取钱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 }

 

 

 这就是线程安全问题:即多个线程先后依次访问共享资源可能造成的问题。

  • 解决方法一:线程同步【核心思想:加锁】

 

 再看运行结果:

 

 

 

  •  解决方法二:同步方法【在处添加关键字synchronized】

 

  •  解决方法三:Lock锁

 

 

 

这篇关于Java --> 多线程1(线程3种创建方式、常用方法、线程安全、线程同步)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!