一些基本概念
线程:基本执行实体
进程:一个进程可以有多个线程
并发:同一时刻交替进行
并行:同一时刻同时进行
进程和线程
进程:是正在运行的程序
独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位
动态性:进程的实质是程序的一次执行过程,进程是动态产生,动态消亡的
并发性:任何进程都可以同其他进程一起并发执行线程:是进程中的单个顺序控制流,是一条执行路径
线程:是进程中的单个顺序控制流,是一条执行路径
单线程:一个进程如果只有一条执行路径,则称为单线程程序
多线程:一个进程如果有多条执行路径,则称为多线程程序
通俗来说:多线程就是让程序同时做多件事情,目的是提高效率
实现多线程
方式一:继承Thread类
public class MyThread extends Thread{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName() +"helloWorld");
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
/*
* 多线程的第一种启动方式:
* 1. 自己定义一个类继承Thread
* 2. 重写run方法
* 3. 创建子类的对象,并启动线程
* */
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
MyThread t3 = new MyThread();
t1.setName("线程1");
t2.setName("线程2");
t3.setName("线程3");
t1.start();
t2.start();
t3.start();
}
}
方式二:实现Runnable接口
public class MyRun implements Runnable{
@Override
public void run() {
//书写线程要执行的代码
for (int i = 0; i < 100; i++) {
//获取到当前线程的对象
System.out.println(Thread.currentThread().getName() + "HelloWorld!");
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
/*
* 多线程的第二种启动方式:
* 1.自己定义一个类实现Runnable接口
* 2.重写里面的run方法
* 3.创建自己的类的对象
* 4.创建一个Thread类的对象,并开启线程
* */
//创建MyRun的对象
//表示多线程要执行的任务
MyRun mr = new MyRun();
//创建线程对象
Thread t1 = new Thread(mr);
Thread t2 = new Thread(mr);
//给线程设置名字
t1.setName("线程1");
t2.setName("线程2");
//开启线程
t1.start();
t2.start();
}
}
这种方法不能直接使用getName来获取线程的名字,而是先获取当前线程对象,然后再设置线程名
前面两种方法的缺点是?
不能获取多线程执行的执行结果。所以有第三种实现多线程的方法
方式三:实现Callable接口
public class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
//求1~100之间的和
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum = sum + i;
}
return sum;
}
}
public class ThreadDemo2 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyCallable mc = new MyCallable();
//创建FutureTask对象,用于管理线程运行结果
FutureTask<Integer> ft = new FutureTask<>(mc);
Thread t1 = new Thread(ft);
t1.start();
//获取多线程执行的结果
Integer result = ft.get();
System.out.println(result);
}
}
三种实现方式的对比
-
实现Runnable、Callable接口
-
好处: 扩展性强,实现该接口的同时还可以继承其他的类
-
缺点: 编程相对复杂,不能直接使用Thread类中的方法
-
-
继承Thread类
-
好处: 编程比较简单,可以直接使用Thread类中的方法
-
缺点: 可以扩展性较差,不能再继承其他的
-
常用方法:
String | getName() 返回此线程的名称。 |
void | setName(String name) 将此线程的名称更改为等于参数 |
细节: 1、如果我们没有给线程设置名字,线程也是有默认的名字的 格式:Thread-X(X序号,从0开始的) 2、如果我们要给线程设置名字,可以用set方法进行设置,也可以构造方法设置
static Thread | currentThread() 返回对当前正在执行的线程对象的引用。 |
细节: 当JVM虚拟机启动之后,会自动的启动多条线程 其中有一条线程就叫做main线程 它的作用就是去调用main方法,并执行里面的代码 在以前,我们写的所有的代码,其实都是运行在main线程当中
static void | sleep(long millis, int nanos) 导致正在执行的线程以指定的毫秒数加上指定的纳秒数来暂停(临时停止执行),这取决于系统定时器和调度器的精度和准确性。 |
线程休眠。
线程优先级
setPriority()
设置线程优先级,最小是1,最大是10,默认是5
优先级不是绝对的,而是概率问题
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + "---" + i);
}
}
}
public class ThreadDemo {
public static void main(String[] args){
/*
setPriority(int newPriority) 设置线程的优先级
final int getPriority() 获取线程的优先级
*/
//创建线程要执行的参数对象
MyRunnable mr = new MyRunnable();
//创建线程对象
Thread t1 = new Thread(mr,"飞机");
Thread t2 = new Thread(mr,"坦克");
t1.setPriority(1);
t2.setPriority(10);
t1.start();
t2.start();
}
}
守护线程
setDaemon()
public class MyThread1 extends Thread {
@Override
public void run() {
for (int i = 0; i < 10; i++) {
System.out.println(getName() + "---" + i);
}
}
}
public class MyThread2 extends Thread {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println(getName() + "---" + i);
}
}
}
public class Demo {
public static void main(String[] args) {
MyThread1 t1 = new MyThread1();
MyThread2 t2 = new MyThread2();
t1.setName("女神");
t2.setName("备胎");
//把第二个线程设置为守护线程
//当普通线程执行完之后,那么守护线程也没有继续运行下去的必要了.
t2.setDaemon(true);
t1.start();
t2.start();
}
}
出让线程/礼让线程
public class MyThread extends Thread{
@Override
public void run() {//"飞机" "坦克"
for (int i = 1; i <= 100; i++) {
System.out.println(getName() + "@" + i);
//表示出让当前CPU的执行权
Thread.yield();
}
}
}
public class ThreadDemo {
public static void main(String[] args) {
/*
public static void yield() 出让线程/礼让线程
*/
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
t1.setName("飞机");
t2.setName("坦克");
t1.start();
t2.start();
}
}
死锁的条件
1、资源有限
2、同步嵌套
线程池
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 1; i <= 100; i++) {
System.out.println(Thread.currentThread().getName() + "---" + i);
}
}
}
public class MyThreadPoolDemo {
public static void main(String[] args) throws InterruptedException {
/*
public static ExecutorService newCachedThreadPool() 创建一个没有上限的线程池
public static ExecutorService newFixedThreadPool (int nThreads) 创建有上限的线程池
*/
//1.获取线程池对象
ExecutorService pool1 = Executors.newFixedThreadPool(3);
//2.提交任务
pool1.submit(new MyRunnable());
pool1.submit(new MyRunnable());
pool1.submit(new MyRunnable());
pool1.submit(new MyRunnable());
pool1.submit(new MyRunnable());
pool1.submit(new MyRunnable());
//3.销毁线程池
//pool1.shutdown();
}
}