多线程的概述+创建线程的三种方式

一.概述

1.多进程的概述

A:线程和进程
		要想说线程,首先必须得聊聊进程,因为线程是依赖于进程存在的。
	B:进程概述
		什么是进程呢?通过任务管理器我们就可以看到进程的存在。
		概念:进程就是正在运行的程序,是系统进行资源分配和调用的独立单位。
					  每一个进程都有它自己的内存空间和系统资源。
	C:多进程的意义
		单进程计算机只能做一件事情。而我们现在的计算机都可以一边玩游戏(游戏进程),一边听音乐(音乐进程),
		所以我们常见的操作系统都是多进程操作系统。比如:Windows,Mac和Linux等,能在同一个时间段内执行多个任务。
		对于单核计算机来讲,游戏进程和音乐进程是同时运行的吗?不是。
		因为CPU在某个时间点上只能做一件事情,计算机是在游戏进程和音乐进程间做着频繁切换,且切换速度很快,
		所以,我们感觉游戏和音乐在同时进行,其实并不是同时执行的。多进程的作用不是提高执行速度,而是提高CPU的使用率。

2.多线程的概述

A:什么是线程
		在一个进程内部又可以执行多个任务,而这每一个任务我们就可以看成是一个线程。是程序使用CPU的基本单位。
		所以,进程是拥有资源的基本单位, 线程是CPU调度的基本单位。
	B:多线程有什么意义呢?
		多线程的作用不是提高执行速度,而是为了提高应用程序的使用率。
		那么怎么理解这个问题呢?
		我们程序在运行的使用,都是在抢CPU的时间片(执行权),如果是多线程的程序,那么在抢到
		CPU的执行权的概率应该比较单线程程序抢到的概率要大.那么也就是说,CPU在多线程程序
		中执行的时间要比单线程多,所以就提高了程序的使用率.但是即使是多线程程序,那么他们
		中的哪个线程能抢占到CPU的资源呢,这个是不确定的,所以多线程具有随机性.
	C:大家注意两个词汇的区别:并行和并发。
		前者是逻辑上同时发生,指在某一个时间内同时运行多个程序。
		后者是物理上同时发生,指在某一个时间点同时运行多个程序。



 什么是并发 ?
       并发 : 指应用能够交替执行不同的任务, 其实并发有点类似于多线程的原理, 多线程并非是如果你开两个线程同时执行多个任务。
 执行, 就是在你几乎不可能察觉到的速度不断去切换这两个任务, 已达到"同时执行效果", 其实并不是的, 只是计算机的速度太快, 我们无法察觉到而已. 就类似于你, 吃一口饭喝一口水, 以正常速度来看, 完全能够看的出来, 当你把这个过程以n倍速度执行时..可以想象一下.
        
 什么是并行 ?
     并行 : 指应用能够同时执行不同的任务, 例:吃饭的时候可以边吃饭边打电话, 这两件事情可以同时执行
        

3.java程序运行原理

A:Java程序运行原理
		Java命令会启动java虚拟机,启动JVM,等于启动了一个应用程序,也就是启动了一个进程。
		该进程会自动启动一个 “主线程” ,然后主线程去调用某个类的 main 方法。
		所以 main方法运行在主线程中。
	B:JVM的启动是多线程的吗:		JVM启动至少启动了垃圾回收线程和主线程,所以是多线程的。

二.多线程的实现方式一

1.概述

	A:如何实现多线程:
	如何实现呢?
		由于线程是依赖进程而存在的,所以我们应该先创建一个进程(JVM)出来。
	  		而进程是由系统创建的,所以我们应该去调用系统功能创建一个进程。
	  		但是Java是不能直接调用系统功能的,所以,我们没有办法直接实现多线程程序。
	  		但是呢?Java可以去调用C/C++写好的程序来实现多线程程序。
	  		由C/C++去调用系统功能创建进程,然后由Java去调用这样的东西,
	  		然后提供一些类供我们使用。我们就可以实现多线程程序了。
		参考 Thread类
		B:多线程程序实现的方式1
			a:继承Thread类
			b:步骤:
			
       		 1.将一个类声明为 Thread 的子类。
     		   2.该子类应重写 Thread 类的 run 方法。
        		3.接下来可以分配并启动该子类的实例
			c:几个小问题:
			
				启动线程使用的是那个方法:start()方法
				线程能不能多次启动:不能,会报异常
				run()和start()方法的区别
	 我们启动线程使用不是run方法,而应该是start方法.使该线程开始执行;
		 Java 虚拟机调用该线程的 run 方法。
	     
	     为什么要重写run方法?
	这个类是一个线程类,那么在这个类中我们可不可以写一些其他的方法呢?		
	   我们可以在写其他的方法,那么其他方法中封装的代码都是需要被我们线程执行的吗? 不一定
	   那么也就是run方法中封装应该是必须被线程执行的代码.
	   
	 run方法中的代码的书写原则: 一般是比较耗时的代码

2.注意事项

1.正确开启一个线程的方式是调用 start();当线程开启后,由子线程去调用run()方法来执行run()方法里面的代码
2.线程不要重复开启 重复开启会抛异常。IllegalThreadStateException

package org.westos.demo2;

public class MyTest {
    public static void main(String[] args) {
        System.out.println("主线程代码执行");
        System.out.println("主线程代码执行");
        System.out.println("主线程代码执行");
        //Java给我们提供好了一个类 Thread 通过这个类,进创建线程,和开启线程。


        /*创建线程的第一种方式:
        1.将一个类声明为 Thread 的子类。
        2.该子类应重写 Thread 类的 run 方法。
        3.接下来可以分配并启动该子类的实例。
        *
        * */

        System.out.println("当主线程执行到此处时,出现耗时操作,开启子线程来执行耗时代码");
        //创建一个线程
        MyThread myThread = new MyThread();

        //调用run()方法不会开启线程,只是简单的new对象调方法
        //myThread.run();

        //调用start()方法开启线程
        myThread.start();
        //线程重复开启,会报IllegalThreadStateException异常
        //myThread.start();

        System.out.println("下面的代码1");
        System.out.println("下面的代码1");
        System.out.println("下面的代码1");
        System.out.println("下面的代码1");

        MyThread myThread2 = new MyThread();
        myThread2.start();
        System.out.println("下面的代码2");
        System.out.println("下面的代码2");
        System.out.println("下面的代码2");
        
        /*结果是先打印下面的代码1,在打印下面的代码2,最后打印两个耗时操作
        * */
    }
}
--------------------------
package org.westos.demo2;

public class MyThread extends Thread{

    @Override
    public void run() {
        //run 方法里面写的代码是,将来让这个子线程来执行的代码,一般来说我们会把一些耗费时间的代码让子线程来操作,
        // 而不会写到主线程,去阻塞主线程,来提高用户的体验。
        //模拟耗时操作
        for (int i = 0; i < 100; i++) {
            System.out.println(i);
        }
    }
}

3.获取和设置线程对象名称

	A:Thread类的基本获取和设置方法
		public final String getName()//获取线程名称
		public final void setName(String name)//设置线程名称
		其实通过构造方法也可以给线程起名字
		思考:
			如何获取main方法所在的线程名称呢?
			public static Thread currentThread()//获取当前执行的线程
			
		  我们现在是想获取主线程的名称,那么我们可不可以先获取到主线程,
		 如果我们能获取到主线程,那么我们就可以调用getName方法获取对应的名称.
		 如何获取主线程呢? public static Thread currentThread()返回对当前正在执行的线程对象的引用。 
		 
package org.westos.demo2;

public class MyThread extends Thread{
    @Override
    public void run() {
        //模拟耗时操作
        for (int i = 0; i < 100; i++) {
            //System.out.println(i);
            //this.getName() 获取线程的名字
            //System.out.println("线程"+this.getName()+i);
              //获取当前正在执行的线程对象
            Thread thread = Thread.currentThread();
            String name = thread.getName();
            System.out.println("线程:" + name + ":" + i);
        }
    }
}

-----------------------------------
package org.westos.demo2;

public class MyTest {
    public static void main(String[] args) {
        System.out.println("主线程执行了");
        // currentThread(); 获取当前执行的线程对象

        Thread th1 = Thread.currentThread();
        System.out.println(th1);

        th1.setName("主线程");
        String name = th1.getName();
        System.out.println(name);

        MyThread th2 = new MyThread();
        MyThread th3 = new MyThread();
        MyThread th4 = new MyThread();
        //多个线程并发执行()多个抢占CPU的执行权,哪个线程抢到,
        // 在某一个时刻,就会执行哪个线程。线程的执行具有随机性。
        th2.setName("李白");
        th3.setName("杜甫");
        th4.setName("王维");
        th2.start();
        th3.start();
        th4.start();
    }
}

4.复制一个文本,一个视频

package org.westos.demo4;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.WeakHashMap;

public class CopyTextThread extends Thread {
    @Override
    public void run()  {
        //复制文本
        FileInputStream in=null;
        FileOutputStream out=null;
        try {
             in = new FileInputStream("MyTest.java");
             out = new FileOutputStream("MyTest2.java");

            int len=0;
            byte[] bytes = new byte[1024 * 8];

            while ((len=in.read(bytes))!=-1){
                out.write(bytes,0,len);
                out.flush();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                in.close();
                out.close();
            }catch (IOException e){
                e.printStackTrace();
            }

        }
    }
}
------------------------
package org.westos.demo4;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class CopyVideoThread extends Thread{
    @Override
    public void run() {
        //复制视频
        try {
            FileInputStream in = new FileInputStream("Rec 2020-06-06 0001.mp4");
            FileOutputStream out = new FileOutputStream("C:\\Users\\user\\Desktop\\aa.mp4");
            int len=0;
            byte[] bytes = new byte[1024 * 8];
            while ((len=in.read(bytes))!=-1){
                out.write(bytes,0,len);
                out.flush();
            }
            in.close();
            out.close();
        }catch (IOException e){
            e.printStackTrace();
        }

    }
}
---------------------------
package org.westos.demo4;

public class MyTest {
    public static void main(String[] args) {
        //复制一个文本,一个视频
        System.out.println("主线程执行了");
        CopyTextThread th1 = new CopyTextThread();
        th1.start();
        CopyVideoThread th2 = new CopyVideoThread();
        th2.start();
        System.out.println("下面的代码");
        System.out.println("下面的代码");
        System.out.println("下面的代码");
    }
}

5.线程调度及获取和设置线程优先级

	A:线程的执行
		假如我们的计算机只有一个 CPU,那么 CPU 在某一个时刻只能执行一条指令,
		线程只有得到 CPU时间片,也就是使用权,才可以执行指令。那么Java是如何对线程进行调用的呢?
	B:线程有两种调度模型:
		分时调度模型   	所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片
		抢占式调度模型   优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,
						优先级高的线程获取的 CPU 时间片相对多一些。 
						Java使用的是抢占式调度模型。
						
	C:如何设置和获取线程优先级
		public final int getPriority() //获取线程的优先级
		public final void setPriority(int newPriority)//设置线程的优先级
		优先级从1-10,1最小,10最大,默认优先级为5
		  那么这个默认的优先级是多少呢,以及我们如何来获取线程的优先级.
  获取线程的优先级:	
 		public final int getPriority()返回线程的优先级。 
  线程的默认优先级是5
  
  给线程设置优先级:
  		public final void setPriority(int newPriority)
		
注意事项:  有的时候我们给线程设置了指定的优先级,但是该线程并不是按照优先级高的线程执行,那是为什么呢?
	- 因为线程的优先级的大小仅仅表示这个线程被CPU执行的概率增大了.但是我们都知道多线程具有随机性,
	- 所以有的时候一两次的运行说明不了问题
package org.westos.demo5;

import sun.plugin2.gluegen.runtime.CPU;

public class MyTest {
    public static void main(String[] args) {
        /* A:
        线程的执行
        假如我们的计算机只有一个 CPU,那么 CPU 在某一个时刻只能执行一条指令,
        线程只有得到 CPU时间片,也就是使用权,才可以执行指令。那么Java是如何对线程进行调用的呢?

        B:
        线程有两种调度模型: th1 th2 th3
        分时调度模型 所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片

        抢占式调度模型 优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,
        优先级高的线程获取的 CPU 时间片相对多一些。
        Java使用的是抢占式调度模型。*/

        MyThread th1 = new  MyThread();

        MyThread th2 = new MyThread();
        MyThread th3 = new MyThread();

        //设置线程的优先级 范围1--10
        th1.setPriority(1);
        th2.setPriority(2);
        th3.setPriority(Thread.MAX_PRIORITY);


        //多个线程并发执行()多个线程抢占CPU的执行权,哪个线程抢到,在某一个时刻,就会执行哪个线程。线程的执行具有随机性。
        //获取线程的优先级
        int priority1 = th1.getPriority();
        int priority2 = th2.getPriority();
        int priority3= th3.getPriority();
        //线程默认的优先级是5,优先级从1-10
        //
        System.out.println("线程的优先级"+ priority1);
        System.out.println("线程的优先级" + priority2);
        System.out.println("线程的优先级" + priority3);
        //Thread.MAX_PRIORITY;
        //Thread.MIN_PRIORITY;
        //Thread.NORM_PRIORITY
        th1.setName("李白");
        th2.setName("杜甫");
        th3.setName("王维");

        th1.start();
        th2.start();
        th3.start();
    }
}
----------------------
package org.westos.demo5;

public class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            //谁调用start()方法,打印的就是谁的名字
            System.out.println("线程"+this.getName()+":"+i);
        }
    }
}

三.多线程中的方法

1.休眠线程

public static void sleep(long millis) 线程休眠
注意:在哪个线程里面调用sleep()方法就休眠哪个线程。
package org.westos.demo;

public class MyThread extends Thread{
    public MyThread() {

    }
    public MyThread(String name){
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(i);
            try {
                //让MyThread这个线程休眠
                Thread.sleep(4000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
----------------------
package org.westos.demo;

public class MyTest {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("main线程开始执行");
        //public static void sleep(long millis) 线程休眠

        Thread.sleep(2000);
        //Thread(String name) 分配新的 Thread 对象。
        //通过有参构造,可以给线程起个名字

        MyThread th1 = new MyThread("th1");
        MyThread th2 = new MyThread("th2");
        th1.start();
        th2.start();
    }
}


2.加入线程

A:
        加入线程:
        public final void join ()
        意思就是:等待该线程执行完毕了以后, 其他线程才能再次执行
        注意事项:
        在线程启动之后, 在调用方法
        join ()可以让多个线程并发执行,变成串行(挨个排队执行,不用抢)
package org.westos.demo2;

public class MyThread extends Thread{
    public MyThread() {
    }
    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            //System.out.println(i);
            System.out.println(Thread.currentThread().getName()+"==="+i);
        }

    }
}
-------------------------
package org.westos.demo2;

public class MyTest {
    public static void main(String[] args) throws InterruptedException {
        MyThread th1 = new MyThread("th1");
        MyThread th2 = new MyThread("th2");
        /*A:
        加入线程:
        public final void join ()
        意思就是:等待该线程执行完毕了以后, 其他线程才能再次执行
        注意事项:
        在线程启动之后, 在调用方法
        join ()可以让多个线程并发执行,变成串行(挨个排队执行,不用抢)*/
        th1.start();
        //  //注意:在线程启动之后, 在调用join()方法
        th1.join();
        th2.start();
        th2.join();
    }
}

3.礼让线程

A:礼让线程:	public static void yield():	暂停当前正在执行的线程对象,并执行其他线程。
B:
按照我们的想法,这个礼让应该是一个线程执行一次,但是通过我们的测试,效果好像不太明显.
	那是为什么呢?
	这个礼让是要暂停当前正在执行的线程,这个暂停的时间是相当短的,如果在这个线程暂停完毕以后,其他的线程还没有
	抢占到CPU的执行权,那么这个时候这个线程应该再次和其他线程抢占CPU的执行权. 
package org.westos.demo3;

public class MyThread extends Thread{
    public MyThread() {
    }
    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            //System.out.println(i);

            //线程礼让
            Thread.yield();
            System.out.println(Thread.currentThread().getName()+"==="+i);
        }

    }
}
------------------------
package org.westos.demo3;

public class MyTest {
    public static void main(String[] args) {
        //礼让线程

        MyThread th1 = new MyThread("th1");
        MyThread th2 = new MyThread("th2");

        th1.start();
        th2.start();
    }
}

4.守护线程

	A:守护线程:	public final void setDaemon(boolean on):
		将该线程标记为守护线程,当用户线程结束后,那么守护线程,就要马上结束。

Java用户线程和守护线程
1.用户线程和守护线程的区别
    用户线程和守护线程都是线程,区别是Java虚拟机在所有用户线程dead后,程序就会结束。而不管是否还有守护线程还在运行,若守护线程还在运行,则会马上结束。很好理解,守护线程是用来辅助用户线程的,如公司的保安和员工,各司其职,当员工都离开后,保安自然下班了。
    
 2.用户线程和守护线程的适用场景
    由两者的区别及dead时间点可知,守护线程不适合用于输入输出或计算等操作,因为用户线程执行完毕,程序就dead了,适用于辅助用户线程的场景,如JVM的垃圾回收,内存管理都是守护线程,还有就是在做数据库应用的时候,使用的数据库连接池,连接池本身也包含着很多后台线程,监听连接个数、超时时间、状态等。
    
 3.创建守护线程
    调用线程对象的方法setDaemon(true),设置线程为守护线程。
            1)thread.setDaemon(true)必须在thread.start()之前设置。
            2)在Daemon线程中产生的新线程也是Daemon的。
            3)不是所有的应用都可以分配给Daemon线程来进行服务,比如读写操作或者计算逻辑。
    因为Daemon Thread还没来得及进行操作,虚拟机可能已经退出了。
    
 4.Java守护线程和Linux守护进程
    两者不是一个概念。Linux守护进程是后台服务进程,没有控制台。
    在Windows中,你可以运行javaw来达到释放控制台的目的,在Unix下你加&在命令的最后就行了。所以守护进程并非一定需要的。
package org.westos.demo4;

public class MyThread extends Thread{
    public MyThread() {
    }
    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            String name = Thread.currentThread().getName();
            System.out.println(name+"==="+i);
        }
    }
}
-----------------------------
package org.westos.demo4;

public class MyTest {
    public static void main(String[] args) {
        String name = Thread.currentThread().getName();
        System.out.println(name);

        Thread.currentThread().setName("刘备");
        System.out.println(Thread.currentThread().getName());

        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"=="+i);
        }

        MyThread th1 = new MyThread();
        MyThread th2 = new MyThread();
        th1.setName("张飞");
        th2.setName("关羽");
        //设置为守护线程 当主线程死亡后,守护线程要立马死亡掉。
        //注意:setDaemon(true)该方法必须在启动线程前调用。
        th1.setDaemon(true);
        th2.setDaemon(true);
        th1.start();
        th2.start();


    }
}

5.中断线程

A:中断线程
		public final void stop():		停止线程的运行
		public void interrupt():		清除线程的阻塞状态,查看API可得当线程调用
										wait(),sleep(long time)方法的时候处于阻塞状态,
										可以通过这个方法清除阻塞
package org.westos.demo5;

public class MyThread extends Thread{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            //线程休眠,就是线程处于了一种阻塞状态
            try {
                Thread.sleep(2000);

                System.out.println(Thread.currentThread().getName()+"==="+i);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
------------------
package org.westos.demo5;

public class MyTest {
    public static void main(String[] args) throws InterruptedException {
        //中断线程

        MyThread th1 = new MyThread();
        th1.setName("th1");
        th1.start();

        //线程休眠,就是线程处于了一种阻塞状态
        Thread.sleep(2000);
        //停止线程的运行
        //th1.stop();
        //清除线程的阻塞状态
        th1.interrupt();
    }
}

四.创建线程的第二种方式

1.概述

A:实现Runnable接口  这种方式扩展性强 实现一个接口 还可以再去继承其他类
		a:如何获取线程名称
		b:如何给线程设置名称
		c:实现接口方式的好处
			可以避免由于Java单继承带来的局限性。
package org.westos.demo6;

public class MyRunnable implements Runnable {
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            //注意这里没有this关键字,Runnable没有getName()方法,Thread里有getName()方法
           // System.out.println(this.getName()+"==="+i);

            System.out.println(Thread.currentThread().getName()+"==="+i);
        }
    }
}
----------------------------
package org.westos.demo6;

public class MyRunnable2 implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+"==="+i);
        }
    }
}
--------------------------------
package org.westos.demo6;

public class MyTest {
    public static void main(String[] args) {
      /*   创建线程的第二种方式
        1. 定义一个类实现 Runnable 接口。
        2.重写该接口 run 方法。
         3.然后可以分配该类的实例,
        4在创建 Thread 对象时作为一个参数来传递并启动。
        这种方式扩展性强 实现一个接口 还可以再去继承其他类

       Thread(Runnable target)
        分配新的 Thread 对象。*/

        // Runnable 任务 接口应该由那些打算通过某一线程执行其实例的类来实现。

        MyRunnable myRunnable = new MyRunnable();
        Thread th1 = new Thread(myRunnable);
        th1.setName("th1");
        th1.start();

        Thread th2 = new Thread(new MyRunnable2());
        th2.setName("th2");
        th2.start();
    }
}

2.构造方法

Thread(Runnable target, String name)
        分配新的 Thread 对象。
package org.westos.demo7;

public class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName()+"==="+i);
        }
    }
}
--------------------
package org.westos.demo7;

public class MyTest {
    public static void main(String[] args) {
         /*  Thread(Runnable target, String name)
        分配新的 Thread 对象。*/
        MyRunnable myRunnable = new MyRunnable();

        Thread th1 = new Thread(myRunnable, "th1");
        Thread th2 = new Thread(myRunnable, "th2");
        th1.start();
        th2.start();
    }
}

五.创建线程的第三种方式

1.概述

A:实现 Callable 接口。 相较于实现 Runnable 接口的方式,方法可以有返回值,并且可以抛出异常。
	  
	    B:执行 Callable 方式,需要 FutureTask 实现类的支持,用于接收运算结果。  FutureTask 是  Future 接口的实现类
	
	C:实现步骤
		1.创建一个类实现Callable 接口
		2.创建一个FutureTask类将Callable接口的子类对象作为参数传进去
		3.创建Thread类,将FutureTask对象作为参数传进去
		4.开启线程
package org.westos.demo8;

import java.util.concurrent.Callable;

public class MyCallable implements Callable<Integer> {
    private int num;

    public MyCallable(int num) {
        this.num = num;
    }

    //call()方法 让线程来执行的方法
    @Override
    public Integer call() throws Exception {
        //求1-num之间的和
        int sum=0;
        for (int i = 1; i <= num; i++) {
            sum+=i;
        }
        return sum;
    }
}
----------------------------------
package org.westos.demo8;

import javax.swing.text.TabableView;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class MyTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //创建线程的第三种方式
        /* C:
        实现步骤
        1. 创建一个类实现Callable 接口 重写接口中的call方法
        2. 创建一个FutureTask类将Callable接口的子类对象作为参数传进去
        3. 创建Thread类, 将FutureTask对象作为参数传进去
        4. 开启线程*/

        //这种方式可以获取子线程执行完之后的结果。
        MyCallable myCallable = new MyCallable(100);
        FutureTask<Integer> task = new FutureTask<>(myCallable);
        Thread th1 = new Thread(task);
        th1.start();

        //获取线程执行完之后返回的结果
        Integer integer = task.get();
        System.out.println(integer);

        MyCallable myCallable2 = new MyCallable(20);
        FutureTask<Integer> task2 = new FutureTask<>(myCallable2);
        Thread th2 = new Thread(task2);
        th2.start();

        //获取返回值
        Integer integer2 = task2.get();
        System.out.println(integer2);

        //Runnable 任务 让线程来执行 run() 没有返回值,这个方法不能抛出异常,只能抓

        //Callable 任务 让线程来执行 call() 有返回值,而且可以抛出异常。

    }
}

六.卖电影票案例

1.通过继承Thread类实现

需求:某电影院目前正在上映贺岁大片,共有100张票,而它有3个售票窗口售票,请设计一个程序模拟该电影院售票。
		通过继承Thread类实现
	
	 分析:
	 a: 三个窗口其实就是3个线程
	 b: 定义票的数量100张
	 c: 创建线程对象,启动线程. 每卖一张这个票数应该--

package org.westos.demo9;

public class MyThread extends Thread{
    //2.设置票数为共享数据,让三个线程来共享
    static int piao = 100;
    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        /*1.这样写每个窗口都会卖1-100张票*/
        /*for (int piao = 100; piao > 0; piao--) {
            String name = Thread.currentThread().getName();

            System.out.println(name+"==="+piao);
        }*/
        while (true){
            if(piao>=1){
                System.out.println(this.getName()+"正在出售第:"+(piao--)+" 张票");
            }
        }
       /* for (piao=100;piao>0;piao--){
            System.out.println(this.getName()+"==="+piao);
        }*/
    }
}
-------------
package org.westos.demo9;

public class MyTest {
    public static void main(String[] args) {
        /*某电影院目前正在上映贺岁大片,共有100张票,而它有3个售票窗口售票,请设计一个程序模拟该电影院售票。
        通过继承Thread类实现*/

        MyThread th1 = new MyThread("窗口1");
        MyThread th2 = new MyThread("窗口2");
        MyThread th3 = new MyThread("窗口3");

        th1.start();
        th2.start();
        th3.start();

    }
}

2.实现Runnable接口

需求:某电影院目前正在上映贺岁大片,共有100张票,而它有3个售票窗口售票,请设计一个程序模拟该电影院售票。
		通过实现Runnable接口实现
package org.westos.demo91;

public class MyRunnable implements Runnable{
    static int piao=100;
    @Override
    public void run() {

        while (true){
            if (piao>0){
                System.out.println(Thread.currentThread().getName()+"正在出售第:"+(piao--)+" 张票");
            }
        }
    }
}
----------------------
package org.westos.demo91;

public class MyTest {
    public static void main(String[] args) {
        //任务类
        MyRunnable myRunnable = new MyRunnable();

        Thread th1 = new Thread(myRunnable);
        Thread th2 = new Thread(myRunnable);
        Thread th3 = new Thread(myRunnable);
        th1.start();
        th2.start();
        th3.start();
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值