关于多线程的创建和执行

1.多线程的意义
共享资源:每一个运行的程序可能包括多个独立运行的线程(Thread)。 线程(Thread)是一份独立运行的程序,有自己专用的运行栈。线程有可能和其他线程共享一些资源,比如,内存,文件,数据库等。
同步”:其实恰恰相反,线程同步的真实意思,其实是“排队”:几个线程之间要排队,一个一个对共享资源进行操作,而不是同时进行操作(如存取钱,必须要存取完成且成功过后,账目才能尽心相应增减,如发生意外,则需要等待,或者反馈失败)。
共享”:只有共享资源的读写访问才需要同步,如果不是共享资源,那么就根本没有同步的必要。
变量”:只有“变量”才需要同步访问。只要这些线程的代码访问同一份可变的共享资源,这些线程之间就需要同步,即需要在访问“变量”之前要先获得权力(避免差异就需要加锁:但是综合研究,同步锁不是加在共享资源上,而是加在访问共享资源的代码段上。)。
优点:(1)进程之间不能共享内存,但线程之 间可以,且十分容易
(2)系统创建进程是需要为该进程重新分配系统资源,但创建线程则代价小得多,因此使用多线程来实现多任务并发比多进程的效率高。
应用:(1)一个浏览器必须能同时下载多个图片
(2)一个web服务器必须能同时相应多个用户请求
(3)Java虚拟机本身就在后台提供了一个超级线程来进行垃圾回收
2.多线程的创建
Java 提供了三种创建线程的方法:

1.通过实现 Runnable 接口;
2.通过继承 Thread 类本身;
3.通过 Callable 和 Future 创建线程。
a.例 创建一个实现Runnable接口的类

	package com.meiman.meimanwallet.thread;

class RunnableDemo implements Runnable {
private String thread;
private Thread t;

public RunnableDemo(String thread) {
    this.thread = thread;
}

@Override
public void run() {
    System.out.println("Runing:"+thread);
    try {
        for(int i=4;i>0;i--){
            System.out.println("Thread:"+thread+","+i);
           Thread.sleep(5000);
        }
    } catch (Exception e) {
        System.out.println("Thread:"+thread+":exception");
    }
    System.out.println("Thread:"+thread+":over");
}

public void start(){
    System.out.println("Thread:"+thread+":start");
    if(t==null){
        t=new Thread(this,thread);
        t.start();
    }
}
}

public class TestThread {

public static void main(String args[]) {
    //r1,r2调用是通过new RunnableDemo 就是多线程同时执行,通过先调start,才自动执行run
    //如果r1直接调run,r2在下不管是start还是run都必须要等到上面的r1执行完毕(即上一个run执行完毕)过后才开始执行,我觉得这就是"同步"
    //如果都是只调start,则会同时进行
    RunnableDemo r1 = new RunnableDemo("Thread-1");
    r1.run();
    RunnableDemo r2 = new RunnableDemo("Thread-2");
    r2.run();
}
}

执行结果:

	Creating Thread-1
	Starting Thread-1
	Creating Thread-2
	Starting Thread-2
	Running Thread-1
	Thread: Thread-1, 4
	Running Thread-2
	Thread: Thread-2, 4
	Thread: Thread-1, 3
	Thread: Thread-2, 3
	Thread: Thread-1, 2
	Thread: Thread-2, 2
	Thread: Thread-2, 1
	Thread: Thread-1, 1
	Thread Thread-1 exiting.
	Thread Thread-2 exiting.
	Process finished with exit code 0

b.通过继承Thread来创建线程
创建一个线程的第二种方法是创建一个新的类,该类继承 Thread 类,然后创建一个该类的实例。
继承类必须重写 run() 方法,该方法是新线程的入口点。它也必须调用 start() 方法才能执行。
该方法尽管被列为一种多线程实现方式,但是本质上也是实现了 Runnable 接口的一个实例,就是
把 class RunnableDemo implements Runnable {}
变成了class RunnableDemo extends Thread {}

Thread的一些方法,通过Thread对象调用:
关于多线程的创建和执行
Thread的一些静态方法:
关于多线程的创建和执行
c.通过 Callable 和 Future 创建线程

  1. 创建 Callable 接口的实现类,并实现 call() 方法,该 call() 方法将作为线程执行体,并且有返回值。

  2. 创建 Callable 实现类的实例,使用 FutureTask 类来包装 Callable 对象,该 FutureTask 对象封装了该 Callable 对象的 call() 方法的返回值。

  3. 使用 FutureTask 对象作为 Thread 对象的 target 创建并启动新线程。

  4. 调用 FutureTask 对象的 get() 方法来获得子线程执行结束后的返回值。

      public class CallableThreadTest implements Callable<Integer> {
         public static void main(String[] args)  
         {  
             CallableThreadTest ctt = new CallableThreadTest();  
             FutureTask<Integer> ft = new FutureTask<>(ctt);  
             for(int i = 0;i < 100;i++)  
             {  
                 System.out.println(Thread.currentThread().getName()+" 的循环变量i的值"+i);  
                 if(i==20)  
                 {  
                     new Thread(ft,"有返回值的线程").start();  
                 }  
             }  
             try  
             {  
                 System.out.println("子线程的返回值:"+ft.get());  
             } catch (InterruptedException e)  
             {  
                 e.printStackTrace();  
             } catch (ExecutionException e)  
             {  
                 e.printStackTrace();  
             }  
       
         }
         @Override  
         public Integer call() throws Exception  
         {  
             int i = 0;  
             for(;i<100;i++)  
             {  
                 System.out.println(Thread.currentThread().getName()+" "+i);  
             }  
             return i;  
         }  
     }
    

创建线程的三种方式的对比

  1. 采用实现 Runnable、Callable 接口的方式创建多线程时,线程类只是实现了 Runnable 接口或 Callable 接口,还可以继承其他类。

  2. 使用继承 Thread 类的方式创建多线程时,编写简单,如果需要访问当前线程,则无需使用 Thread.currentThread() 方法,直接使用 this 即可获得当前线程。

3.线程的几个主要概念
线程同步
线程间通信
线程死锁
线程控制:挂起、停止和恢复
4.多线程的使用,可以编写出非常高效的程序,但也可能创建了太多的线程,CPU 花费在上下文的切换的时间将多于执行程序的时间,所以适度使用。

线程这个东西有点东西,学海无涯哦…