Java基础之多线程(二)

本文详细介绍了Java中实现多线程的四种方法:继承Thread类、实现Runnable接口、使用Callable接口结合FutureTask以及利用ExecutorService等高级特性。对比了各种方式的优缺点,如数据共享、线程中断及返回值处理。
摘要由CSDN通过智能技术生成

Java多线程实现方式主要有四种:继承Thread类、实现Runnable接口、实现Callable接口通过FutureTask包装器来创建Thread线程、使用ExecutorService、Callable、Future实现有返回结果的多线程。

其中前两种方式线程执行完后都没有返回值,后两种是带返回值的。 

使用Thread对象的interrupt()方法,打断线程睡眠则会抛出interrupted异常

System.in.read();读取键盘输入

方式一:继承Thread类(线程没有返回值,在java.lang包中

  重写run()方法,调用start()方法执行。

  需要注意的是:为什么多线程的启动不是调用run()方法,而是调用start()方法?

      在Java开发中有一门JNI(Java Native Interface)技术,这门技术的特点,使用Java调用本机操作系统的函数,但是这个技术不能离开特定的操作系统。

如果线程想要执行,需要操作系统分配资源。所以此操作严格来讲需要JVM根据不同的操作系统来实现的。

  start()方法中,使用了native关键字修饰了方法,而native关键字时根据不同的操作系统分配不同的资源。

  start()方法,不仅仅要启动多线程执行的代码,还需要根据不同的操作系统来分配资源

 1 package test;
 2 
 3 public class MyThread  {
 4     public static void main(String[] args) {
 5         Test t1 = new Test("one");
 6         Test t2 = new Test("two");
 7         Test t3 = new Test("three"); 8 /** 9 * 调用Thread类中的start方法,才能进行多线程的操作,而不是run方法 10 * start()方法不仅仅启动多线程代码的执行,还需要根据不同的操作系统分配资源 11 */ 12 try {//调用Thread类中的sleep方法,让线程等待指定的一段时间 13 Thread.sleep(1000); 14 } catch (InterruptedException e) { 15  e.printStackTrace(); 16  } 17  t1.start(); 18  t2.start(); 19  t3.start(); 20  } 21 } 22 23 /** 24 * 继承线程类Thread,重写run()方法,在run方法中实现需要进行的数据操作 25 * @author Administrator 26 * 27 */ 28 class Test extends Thread{ 29 30 private String name; 31 32 public Test(String name) { 33 this.name=name; 34  } 35  @Override 36 public void run() {//需要进行多进程的操作 37 for (int i = 0; i < 100; i++) { 38 System.out.println(name+"===>"+i); 39  } 40  } 41 }

 方式二:实现Runnable接口(线程没有返回值,在java.lang包中)

  该接口标注为:@Java.lang.FactionInterface

    实现run方法,将Runnable对象作为参数放入到Thread构造方法中,在调用start()方法。

 1 package test;
 2 /**
 3  * 测试Runnable接口
 4  * @author Administrator
 5  *
 6  */
 7 public class MyRunnable {
 8     public static void main(String[] args) {
 9         Demo mr1 = new Demo("A");
10         Demo mr2 = new Demo("B");
11         Demo mr3 = new Demo("C"); 12 //将该对象作为参数,传入到Thread类中,在调用start()方法。 13 new Thread(mr1).start(); 14 new Thread(mr2).start(); 15 new Thread(mr3).start(); 16  } 17 } 18 19 /** 20 * 实现Runnable接口,实现多线程 21 * @author Administrator 22 * 23 */ 24 class Demo implements Runnable { 25 26 private String name; 27 28 public Demo(String name) { 29 this.name = name; 30  } 31 32  @Override 33 public void run() { 34 for (int i = 0; i < 300; i++) { 35 System.out.println(name + "==>" + i); 36  } 37  } 38 39 }

问题一:Thread与Runnable有什么不同?

  1、Thread实现了Runnable接口,使用Runnable接口可以避免单根继承的问题。

  2、Runnable接口实现的多线程可以比Thread类实现的多线程更加清楚的描述数据共享的概念。

问题二:写出两种多线程实现操作?

 1 package test;
 2 /**
 3  * Runnable接口比Thread类更加清楚的描述了数据共享的概念
 4  * @author Administrator
 5  *
 6  */
 7 public class ThreadAndRunnable {
 8 
 9     public static void main(String [] args){
10         TestDemo1 t = new TestDemo1();
11         new Thread(t).start();
12         new Thread(t).start(); 13 new Thread(t).start(); 14 try { 15 Thread.sleep(2000); 16 } catch (InterruptedException e) { 17 // TODO Auto-generated catch block 18  e.printStackTrace(); 19  } 20 System.out.println("=======================================我是分割线======================================="); 21 /** 22 * 这里虽然也可以数据共享, 23 * 但是,TestDemo2已经继承了Thread类,而这里又要new三个Thread类出来, 24 * 区调用start方法,显得多此一举 25 */ 26 TestDemo2 d1 = new TestDemo2(); 27 new Thread(d1).start(); 28 new Thread(d1).start(); 29 new Thread(d1).start(); 30  } 31 32 } 33 34 /** 35 * 实现了Runnable接口的类,可以明显的表示出数据共享的概念 36 * @author Administrator 37 * 38 */ 39 class TestDemo1 implements Runnable{ 40 /** 41 * 买票 42 */ 43 private int numb = 20; 44 45  @Override 46 public void run() { 47 for (int i = 0; i < 200; i++) { 48 if (this.numb > 0) { 49 System.out.println("买票;numb = "+this.numb--); 50  } 51  } 52  } 53 } 54 55 /** 56 * Thread类实现数据共享 57 * @author Administrator 58 * 59 */ 60 class TestDemo2 extends Thread{ 61 private int num = 20; 62  @Override 63 public void run() { 64 for (int i = 0; i < 200; i++) { 65 if(this.num > 0) 66 System.out.println("买票;num = "+this.num--); 67  } 68  } 69 70 }

 

方式三:实现Callable接口通过FutureTask包装器来创建Thread线程(线程有返回值,该接口在java.util.concurrent包中)

1 @java.lang.FactionalInterface
2 public interface Callable<V>{
3   public V call() throws Exception;
4 }

从JDK1.5开始提供一个类java.util.concurrentFutureTask<V>,这个类主要负责Callable接口对象操作的,该类的定义结构为:

 1 public class FutureTask<V> extends Object implements RunnableFuture<V>
 2 
 3 //然而RunnableFuture有是什么?
 4 public interface RunnableFuture<V> extends Runnable,Future<V>
 5 
 6 //然而FutureTask<V>接口的构造方法内,接受了Callable接口对象
 7 public FutureTask(Callable<V> callable)  
 8 //接受callable对象的目的:取得call()方法的结果,只有通过FutureTask类才能得到返回的   //结果
 1 package test;
 2 
 3 import java.util.concurrent.Callable;
 4 import java.util.concurrent.FutureTask;
 5 /**
 6  * Callable接口实现多线程实例,可以得到返回的数据
 7  * @author Administrator
 8  *
 9  */
10 public class MyCllable {
11 
12     public static void main(String[] args) throws Exception{
13         TestDemo t1 = new TestDemo(); 14 TestDemo t2 = new TestDemo(); 15 FutureTask<String> task1 =new FutureTask<String>(t1); 16 FutureTask<String> task2 =new FutureTask<String>(t2); 17 /** 18 * FutureTask类是Runnable接口子类,所以可以作为构造参数调用start()方法 19 */ 20 new Thread(task1).start();//启动多线程 21 new Thread(task2).start();//启动多线程 22 System.out.println("task1===>"+task1.get());//得到返回的结果 23 System.out.println("task2===>"+task2.get());//得到返回的结果 24  } 25 26 } 27 28 class TestDemo implements Callable<String>{ 29 30 private int num = 20; 31 32  @Override 33 public String call() throws Exception { 34 for (int i = 0; i < 200; i++) { 35 if(this.num > 0){ 36 System.out.println("使用Callable接口实现多线程:"+num--); 37  } 38  } 39 return "数据归零"; 40  } 41 42 }

示例:写一个线程类输出001—999启动10条线程同时执行该类,每个线程要都有机会,而且不能重复而其有序

 1 package com.zelin.lesson.test;
 2 
 3 import java.text.NumberFormat;
 4 
 5 /**
 6  * 编写一个线程类,启动10条线程同时执行该类,要求输出效果如下所示
 7  *           001
 8  *            002
 9  *            003
10  *             ….
11  *            999
12  * 输出001—999  每个线程要都有机会,而且不能重复而其有序
13  */
14 public class TestThread {
15     public static void main(String[] args) {
16         Thread0 t = new Thread0();
17         for (int i = 0; i < 10; i++) {
18             new Thread(t).start();
19         }
20     }
21 }
22 
23 class Thread0 implements  Runnable{
24     //1.定义变量
25     private int tickets = 1;
26     @Override
27     public void run() {
28         while(true){
29             synchronized (this){
30                 if(tickets == 1000)  break;
31                 //2.将变量进行格式化处理
32                 NumberFormat numberFormat = NumberFormat.getInstance();
33                 //3.设置输出的数字的最小整数位数
34                 numberFormat.setMinimumIntegerDigits(3);
35                 //4.对数字进行格式化处理
36                 String format = numberFormat.format(tickets++);
37                 //5.输出
38                 System.out.println(format);
39             }
40         }
41     }
42 }

     线程(三)点我

转载于:https://www.cnblogs.com/in-the-game-of-thrones/p/11299225.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值