Java多线程01
java核心概念
- 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为的干预的。
- 对同一份资源操作时,会存在资源抢夺的问题,需要加入并发控制
- 线程会带来额外的开销,如cpu调度时间,并发控制开销
- 每个线程在自己的工作内存交互,加载和存储主内存控制不当会造成数据不一致。
- 线程是程序调度和执行的基本单位,而进程是资源分配的单位
- 线程是进程的一部分,可以称为轻权进程或轻量级进程
- 很多多线程是模拟出来的,真正的多线程是指有多个cpu,即多核;如果是模拟出来的多线程,即一个cpu的情况下,在同一个时间点,cpu只能执行一个代码,因为切换的很快,所以就有同时执行的错觉。
线程的创建
-
继承Thread类
public class ThreadInit{ MyThread mt=new MyThread(); mt.start(); } class MyThread extends Thread{ public void run(){ //线程方法体 } }
-
实现Runnable接口
public class ThreadInit{ MyThread mt=new MyThread(); Thread t=new Thread(mt); t.start(); } class MyThread implements Runnable{ public void run(){ //线程方法体 } }
-
实现Callable接口(可返回线程的结果)
import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; public class MyCallable { public static void main(String[] args) { /****************方法一******************/ //创建目标对象 CallStudy cs=new CallStudy("线程"); //创建执行服务 FutureTask ft=new FutureTask(cs); //创建线程对象、关联目标对象、启动线程 new Thread(ft).start(); //主线程程序 for(int i=97;i<123;i++) { System.out.println((char)i); } //获取线程结果并输出 try { result = (String) ft.get(); System.out.println(result); } catch (InterruptedException | ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } /***************方法二*****************/ //创建目标对象 CallStudy cs=new CallStudy("线程"); //创建执行服务 ExecutorService es=Executors.newFixedThreadPool(1); //提交执行 Future<String> f=es.submit(cs); //主线程程序 for(int i=97;i<123;i++) { System.out.println((char)i); } //获得线程结果 try { String str=f.get(); System.out.println(str); } catch (InterruptedException | ExecutionException e) { // TODO Auto-generated catch block e.printStackTrace(); } //关闭线程服务 es.shutdownNow(); } } //创建实现Callable的类 class CallStudy implements Callable{ private String str; public CallStudy(String str) { super(); this.str = str; } //必须实现call方法,可以返回值 @Override public Object call() throws Exception { // TODO Auto-generated method stub for(int i=0;i<26;i++) { System.out.println(i); } return "call Thread-->"+this.str; } }
**注意:**三种方法中第继承Thread、实现Runnable不能返回结果,而实现Callable能够返回线程结果。
线程状态
线程有五个状态:新生状态、就绪状态、运行状态、阻塞状态、死亡状态。
如下图:
线程状态详解如下图:
线程相关方法
- sleep():使线程停止运行一段时间,此时线程处于阻塞状态。
- join():插队线程,阻塞其它线程,等待该线程执行完后在执行其它线程。
- yield(): 礼让线程,当前线程停止,进入就绪状态,此时CPU调度器重新调度线程(不是进入阻塞状态,“礼让”之后不一定是其它线程先执行,也可能是该线程执行)。
- setDaemon(): 设置守护线程。JVM仅仅确保用户线程执行完,守护线程服务用户线程。
- setPriority(): 设置线程的优先级。可传参:MIN_PRIORITY、NORM_PRIORITY、MAX_PRIORITY。(优先级低只是意味着获得调度的概率低。并不是绝对先调用优先级高后调用优先级低的线程)。
- getPriority(): 得到线程的优先级。
- isAlive():判断线程是否终止。
- setName(): 给线程命名。
- getName(): 得到线程的名字。
- currentThread():获得当前正在运行的线程的对象。
线程的关闭
线程的关闭可以使用stop()方法,但不支持,该方法线程不安全。
可以通过一些变量使线程停止,即线程执行完,如下程序:
package io.github.hu;
public class ThreadStat implements Runnable{
//判断线程是否停止
private boolean flag=true;
private String name;
public void run() {
int i=0;
while(flag) {
System.out.println(name+"--->"+i++);
}
}
public ThreadStat(String name) {
super();
this.name = name;
}
//使线程停止的方法
public void over() {
flag=false;
}
public static void main(String[] args) throws InterruptedException {
ThreadStat ts=new ThreadStat("线程");
new Thread(ts).start();
for(int i=0;i<99;i++) {
//当主线程的i=88时,另一个线程停止
if(i==88) {
Thread.sleep(5);
ts.over();
System.out.println("线程停止");
}
System.out.println("main-->"+i);
}
}
}