Java线程
一,程序,进程,线程
程序:安装在电脑上的程序文件 是静态的
进程:运行中的应用程序,例如运行中的qq。。。。。。,是操作系统分配空间的最小单位
线程:进程可以进一步细化成线程,就是进程中最小的任务单元
cpu执行以线程为单位
线程和进程关系:
一个进程中可以包含多个线程,线程不能脱离进程.
一个进程中至少包含一个线程(主线程 main)
在主线程中可以创建并启动其他线程
main方法启动主线程
在一个线程中的方法顺序进行
二,创建线程
1.继承Thread()类方法
在Java中要实现线程,最简单的方法就是继承Thread类,重写其中的run方法,方法原型如下
package javatheard.demo1;
public class MyThread extends Thread{
/*
线程中要执行的代码或任务都在run()中
*/
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("run" + i );
}
}
}
Thread类中的run()方法本身并不执行任何操作,如果我们重写run方法,当线程启动时,它将执行run方法
package javatheard.demo1;
public class Test {
/*
启动java的主线程
*/
public static void main(String[] args) {
//创建一个线程
MyThread myThread = new MyThread();
myThread.start();//启动线程
//此for循环属于main线程
for (int i = 0; i < 1000; i++) {
System.out.println("main" + i);
}
}
}
2.实现Runnable接口方法
java.lang.Runnable接口中仅仅只有一个抽象方法
public void run()
也可以通过实现Runnable接口的方式来实现线程,只需要实现其中的run方法即可
Runnable接口的存在主要是为了解决Java中不允许多继承的问题
package javatheard.demo2;
public class Task implements Runnable{
/*
实现了Runnable接口的类,并不是线程
是把要执行的任务放在此类的run()中,这个类就可以看出一个任务类
*/
public static void main(String[] args) {
}
/*
run()写线程要执行的任务
*/
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println(i);
}
}
}
package javatheard.demo2;
public class Test {
public static void main(String[] args) {
Task task = new Task();//创建一个任务对象
Thread thread1 = new Thread(task);//创建一个线程对象,并添加一个要执行的任务1
Thread thread2 = new Thread(task);//创建一个线程对象,并添加一个要执行的任务2
thread1.start();
thread2.run();//只实现方法与线程无关
for (int i = 0; i < 1000; i++) {
System.out.println(i);
}
}
}
Runnable接口方式的好处
(1)避免了单继承的局限性
(2)多个线程可以共享同一个接口实现类的对象,非常适合多个相同线程类处理同一份资源
三,Thread类中的常用方法
Thread.sleep(2000);//使该线程休眠多少毫秒
Thread thread1 = new Thread(task,"窗口一");//使用线程,并命名
thread1.setPriority(6);//设置优先级
thread1.setName("jh1");//给对应线程修改名称
System.out.println( Thread.currentThread().getPriority()+" "+Thread.currentThread().getId()+" "+Thread.currentThread().getName());
//返回线程优先级,ID,线程名称
thread1.join();//等待线程结束
线程优先级:
计算机中只有一个cpu,各个线程轮流获得cpu的使用权,才能执行任务
优先级较高的线程有更多获得cpu的机会
优先级使用整数表示,取值范围是1~10;默认情况下优先级为5
Thread类中有3个静态常量表示优先级
MAX_PRIORITY:取值范围为10,表示最高优先级
MIN_PRIORITY:取值为1,表示最低优先级
NOPM_PRIORITY:取值为5,表示默认优先级
注:高优先级线程抢占cpu
四,线程状态
新建:当一个Thread类或其子类的对象被声明并创建时,新生的线程对象处于新建状态
就绪:处于新建状态的线程被start()后,将进入线程队列等待cpu时间片,此时它已具备了运行时条件,只是没分配到cpu资源
运行:当就绪的线程被调度并获得cpu资源时,便进入运行状态,run()方法定义了线程的操作和功能
阻塞:在某种特殊情况下,被认为挂起或执行输入输出操作时,让出cpu并临时终止自己的执行,进入阻塞状态
死亡:线程完成了它的全部工作或线程被提前强制地中止或出现异常导致结束
五,多线程的概念
多线程是指程序中包含多个执行单元,即在一个程序中可以同时运行多
个不同的线程来执行不同的任务,也就是说允许单个程序创建多个并行
执行的线程来完成各自的任务。
1.何时需要多线程
(1)程序需要同时执行两个或多个任务时
(2)程序需要实现一些需要等待的任务时,如用户输入,文件读写操作,网络操作,搜索等
2.多线程的优点
(1)提高程序的响应
(2)提高cpu的利用率
(3)改善程序结构,将复杂任务分为多个线程,独立执行
3.多线程的缺点
线程也是程序,所以线程需要占用内存,线程越多占用内存也越多;
多线程需要协调和管理,所以需要跟踪管理线程,使得cpu开销变大;
线程之间同时对共享资源的访问会相互影响,如果不加以控制会导致数据出错.
六,线程同步
1.多线程同步
多个线程同时读写同一份共享资源时,可能会引起冲突。所以引入线程“同步”机制,
即各线程间要有先来后到;
注:同步就是排队+锁:
几个线程之间要排队,一个个对共享资源进行操作,而不是同时进行操作;
2.同步锁
为了保证数据在方法中被访问时的正确性,在访问时加入锁机制
同步锁可以是java中任意的类的一个对象,此对象必须是唯一的,
此对象时用来记录有没有线程进入到同步代码块中
synchronized(同步锁){
}
一旦有线程进入到同步代码中,同步锁对象就会记录,其他线程就不能进入,
直到进入同步代码块的线程执行离开同步代码块,锁会自动释放
synchronized修饰方法,这个方法为同步方法,
这时同步锁对象就不需要我们自己提供了,会自己提供
当方法如果是非静态方法时,锁对象是this
当方法如果是静态方法时,锁对象是类对象(类对象一个类只有一个)
public static synchronized void print(){
}
七,新增创建线程方法
实现Callable接口与使用Runnable相比,Callable功能更加强大些
(1)相比run()方法,可以有返回值
(2)方法可以抛出异常
(3)支持泛型的返回值
(4)需要借助FutereTask类,获取返回结果
package javatheard.Demo8;
import java.util.concurrent.Callable;
/*
java中第三种创建线程方式,实现Callable接口
重写call()方法
进行了升级
1.可以返回结果
2.可以抛出异常
*/
public class SumTask implements Callable<Integer> {
@Override
public Integer call() throws Exception {
Integer a = 0;
for (int i = 0; i <= 10; i++) {
a+=i;
}
return a;
}
}
package javatheard.Demo8;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Test {
public static void main(String[] args) {
SumTask sumTask = new SumTask();//创建任务对象
FutureTask<Integer> futureTask = new FutureTask<>(sumTask);//创建一个FutureTask对象接受Callable接口的实现类
Thread thread = new Thread(futureTask);//创建线程,接受一个任务
thread.start();//接收线程
try {
Integer a = futureTask.get();//获取线程返回值
System.out.println(a);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
}catch (Exception e){
System.out.println(e.getMessage());
}
}
}