Java学习--线程(一)

 目录

   1.进程与线程

  2.线程的实现方式

  3.线程的生命周期

一、进程与线程

  进程:运行的程序和它所需要的资源(CPU、内存)

  线程:线程是进程的一部分,粒度比进程小,一个进程可以拥有多个线程,至少包含一个线程,这个线程就是主线程。

  线程与进程的区别:

  1.一个进程里面至少拥有一个线程

  2.线程之间使用的资源是共享的。

  3.线程之间的通信比进程间的通信开销小

  4.线程的创建相对于进程的创建容易

ps:1.进程包含线程,可以有多个,至少有一个

  2.线程是独立的,CPU抢占式,也就是当前运行的线程很有可能被暂停(挂起)很小时间片

  3.进程间的内存空间是独立的,但是线程间的内存空间是共享的。

  4.由于共享,线程间运行效率大大提高,利于线程间的通信(数据交换)

  5.线程的创建比进程的创建小的多,使用比较多。

使用多线程的目的:

  最大效率的使用CPU资源,提高程序的运行效率

  ps:真正的多线程是建立在多核CPU的基础上的。

二、线程的实现方式

  1.继承Thread   重写run方法

  2.实现Runnable接口  重写run方法

     3.带返回值的线程创建

   Callable 和FutureTask

   返回值获取方法 FutureTask对象的get()方法

  ps:推荐使用第二种   。原因 :Java类的接口可以多实现,而继承只能单继承

  注:run方法中如果有异常时不能抛出去的。   原因:run方法时重写的,而父类或端口中的run方法是没有申明异常的。

FutureTask的API

 

三、线程的生命周期

创建:实例化一个线程对象 new Thread()
就绪:start方法执行或者阻塞结束后
运行:获得CPU的时间片,执行run方法
阻塞:暂停(挂起),IO、sleep、wait、join
结束:run方法结束或者异常

线程的名称--主线程默认名称是main,子线程的默认名称则是Thread-0,Thread-1...

一下是线程的简单实现代码:

package com.demo.thread;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

/**
* 线程的简单实现
* @author Administrator
*
*/
/**
* 主线程
* @author Administrator
*
*/
public class ThreadExample {
/**
* 主线程里面启动子线程
* @param args
*/
public static void main(String[] args) {
//启动用继承实现的线程
ThreadExample1 threadExample1 = new ThreadExample1();
threadExample1.setName("线程1");
threadExample1.start();
//启动用接口实现的线程
new Thread(new ThreadExample2(),"线程2").start();
//启动带返回值的线程
FutureTask<String> futureTask = new FutureTask<>(new ThreadExample3());
try {
new Thread(futureTask,"线程3").start();
String s = futureTask.get();
System.out.println(Thread.currentThread().getName()+"--------"+s);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
/**
* 继承Thread的线程
* @author Administrator
*
*/
class ThreadExample1 extends Thread{
@Override
public void run() {
super.run();
for(int i = 0;i<10;i++){
System.out.println(Thread.currentThread().getName()+"--------"+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

}
}
/**
* 实现runnable接口的线程
* @author Administrator
*
*/
class ThreadExample2 implements Runnable {

@Override
public void run() {
for(int j=0;j<10;j++){
System.out.println(Thread.currentThread().getName()+"--------"+j);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

}
/**
* 实现callable接口的带返回值的线程
* @author Administrator
*
*/
class ThreadExample3 implements Callable<String>{

@Override
public String call() throws Exception {
return "带返回值得线程";
}
}

线程的优先级

  1-10 从低到高

  默认的优先级是5,优先级越高,获得CPU的时间片越大 

sleep方法

  sleep方法能让线程进入阻塞状态,带一个时间参数(毫秒),经过休眠毫秒数后线程进入就绪状态。会有中断异常抛出

  

yield方法

  yield方法能让线程直接进入就绪状态,会有中断异常抛出。

  

join方法

  join方法能让线程合并,让多个线程合并到一个线程中进入阻塞状态,程序运行将会进入阻塞状态,会有中断异常抛出。

  

以下是join方法的具体代码与结果

package com.demo.thread;

public class JoinDemo {
    public static void main(String[] args) {

        JoinThread thread = new JoinThread();
        thread.start();
        System.out.println("over");
    }
    
}
class JoinThread extends Thread{
    @Override
    public void run() {
        super.run();
        for(int i =0;i<10;i++){
            System.out.println(Thread.currentThread().getName()+"------"+i);
        }
    }
}
不加join方法线程

package com.demo.thread;

public class JoinDemo {
    public static void main(String[] args) throws InterruptedException {

        JoinThread t = new JoinThread();
        t.start();
        t.join();
        System.out.println("over");
    }
    
}
class JoinThread extends Thread{
    @Override
    public void run() {
        super.run();
        for(int i =0;i<10;i++){
            System.out.println(Thread.currentThread().getName()+"------"+i);
        }
    }
}
添加join方法的线程

 

sleep方法与yield方法的区别

  1)sleep方法带参数,可以指定休眠时长,进入阻塞状态CPU让给其他线程,当休眠时间到了后,进入就绪状态。
  2)yield方法没有参数,CPU时间片让给同优先级或者优先级更高的线程,直接进入到就绪状态。有可能刚调用yield方法,又被CPU选中执行。
  3)sleep方法抛出中断异常,yield方法没有
  4)yied方法不太可控,所以一般不推荐使用来控制线程的并发问题sleep方法的可移植性强。

原文地址:https://www.cnblogs.com/bananafish/p/9638802.html