进程:其实就是.exe文件
线程:进程的一个执行单元
1.应用程序包含多个进程
2.进程可以包含多个线程
3.一个java程序其实就是一个进程,一个进程就相当于一个单核cup
并行:同时执行
并发:交替执行
多线程并行:多条线程同时执行
多线程并发:多条线程同时请求执行,但是一个cpu一次只能执行一条线程,所以让其交替执行,但是由于切换速度比较快,所以你看起来像多线程并行
java中研究的就是多线程并发
1.java程序默认会有两条线程,一条是main线程,一条是垃圾回收线程
2.线程的调度是抢占式调度,也就是随机调度
创建线程类
- java使用java.lang.Thread类代表线程,所有的线程对象都必须是Thread类或其子类的实例
- 一条线程执行一段任务(一段代码)
- 创建线程并启动线程的方式
创建线程并启动线程方式一:通过继承Thread类
- 创建一个子类继承Thread类
- 重写从Thread类继承过来的run()方法,把子线程需要执行的代码放入run()方法中
- 创建该子类对象
- 使用该子类对象调用start()方法启动线程
public class MyThread extends Thread{
/**
* 利用继承中的特点
* 将线程名称传递 进行设置
* */
public MyThread(String name){
super(name);
}
/*
* 重写run方法
* 定义线程要执行的代码
* */
public void run(){
for (int i = 0; i < 20; i++) {
//getName()方法 来自父亲
System.out.println(getName()+i);
}
}
}
测试类
public class Demo {
public static void main(String[] args) {
System.out.println("这里是main线程");
MyThread mt = new MyThread("小强");
mt.start();//开启了一个新的线程
for (int i = 0; i < 20; i++) {
System.out.println("旺财:"+i);
}
}
}
创建线程并启动线程方式二:通过实现Runnable接口
- 创建一个实现类实现Runnable接口
- 在实现类中实现run()方法,把子线程需要执行的代码放入run()方法中
- 创建一个Thread类的对象,把实现类的对象作为参数传入
- 调用start()方法启动线程
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
}
public class Demo {
public static void main(String[] args) {
//创建自定义类对象 线程任务对象
MyRunnable mr = new MyRunnable();
//创建线程对象
Thread t = new Thread(mr, "小强");
t.start();
for (int i = 0; i < 20; i++) {
System.out.println("旺财 " + i);
}
}
}
创建线程并启动线程方式三:通过匿名内部类创建线程
1.创建一个Thread类的对象,把Runnable接口的匿名内部类以参数的形式传入,在匿名内部类中指定任务
2.启动线程
new Thread(new Runnable(){
public void run(){
//多线程要执行的代码
}
}).start();
Threed类:
构造方法:
public Thread() :分配一个新的线程对象。
public Thread(String name) :分配一个指定名字的新的线程对象。
public Thread(Runnable target) :分配一个带有指定目标新的线程对象。
public Thread(Runnable target,String name) :分配一个带有指定目标新的线程对象并指定名字。
常用方法:
public String getName() :获取当前线程名称。
public void start() :导致此线程开始执行; Java虚拟机调用此线程的run方法。
public void run() :此线程要执行的任务在此处定义代码。
public static void sleep(long millis) :使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行)。
public static Thread currentThread() :返回对当前正在执行的线程对象的引用。
线程安全问题:使用同步机制来保证线程安全
同步代码块:其实就是对 一段代码进行加锁
概述:synchronized关键字可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问
格式:
synchronized(同步锁){
需要加锁的代码
}
同步锁:
1.可以写任意对象
2.多个线程对象要使用同一把锁
同步方法:其实就是对整个方法进行加锁
概述:使用synchronized修饰的方法,就叫做同步方法,保证A线程执行该方法的时候,其他线程只能在方法外等着。
格式:
修饰符 synchronized 返回值类型 方法名(参数列表){
可以会产生线程安全问题的代码
}
同步锁是谁?
对于非静态static方法,同步锁就是this
对于静态static方法,我们使用当前方法所在类的字节码对象(类名.class)
A线程使用的同步代码块,B线程使用的同步方法,要想让这2个线程同时锁住,那么A和B线程中的同步要一致
Lock锁:ReentrantLock 实现类
Lock锁也称同步锁,加锁与释放锁方法化了,如下:
public void lock(): 加同步锁
public void unlock(); 释放同步锁
condition:
await():等待
signal():唤醒
signalAll():唤醒所有
多条线程想要实现同步,那么锁必须一致。
线程的六种状态:新建、可运行、锁阻塞、无限等待、计时等待、死亡
实现无限等待:
1.使用锁对象调用wait()方法使得线程进入无限等待
2.无限等待线程想要被唤醒,那么必须是其他线程使用锁对象调用notif’y()或者notifyall()方法
3.调用wait()方法和调用notify()或者notifyall()方法的锁对象必须是一致
4.线程进入无限等待之后,不会抢占cpu资源,也不会争夺锁对象
5.无限等待线程被唤醒了,并且获取到了锁对象,那么线程就会继续从进入无限等待的位置开始继续往下执行
线程池:
概念:是一个可以放多个线程的容器,其中的线程可以反复使用
使用线程池中线程对象的步骤:
- 创建线程池对象。
- 创建Runnable接口子类对象。(task)
- 提交Runnable接口子类对象。(take task)
- 关闭线程池(一般不做)。
使用:
方法:
public static ExecutorService newFixedThreadPool(int nThreads) :返回线程池对象。(创建的是有界线 程池,也就是池中的线程个数可以指定最大数量)
// 创建线程池对象
ExecutorService service = Executors.newFixedThreadPool(2);//包含2个线程对象
public Future<?> submit(Runnable task) :获取线程池中的某一个线程对象,并执行
// 从线程池中获取线程对象,然后调用MyRunnable中的run()
service.submit(r);