Java线程
进程
- 运行中的程序,进程时程序的一次执行过程,或正在运行的一个程序,是动态的过程:有它自身的产生、存在和消亡的过程。
线程
- 线程有进程创建,时进程的一个实体
- 一个进程可以拥有多个线程,一个线程也可以有线程
- 单线程:同一时刻只允许运行一个线程
- 多线程:同一时刻可以执行多个线程
- 并发:同一时刻,多个任务交替执行,造成一种“貌似同时”的错觉,简单说单个CPU实现的多任务就是并发
- 并行:同一时刻,多个任务同时执行,多核CPU可以实现并行
- 在电脑中并发和并行可能同时存在
Runtime runtime = Runtime.getRuntime();
int cpuNum = runtime.availableProcessors();
创建线程的方法
- 继承Thread类,重写run方法
- 继承Thread类,该类就是一个线程类,当做线程使用
- Thread类实现了Runable接口中的run方法
- 创建线程对象,调用start()方法,如果调用run方法的话就是一个普通方法。
//主线程退出后进程不一定退出,只有当所有线程全部退出后整个进程才会退出
public class Thread01 {
public static void main(String[] args) throws InterruptedException {
Cat cat = new Cat();
cat.start();//main线程启动一个子线程,主线程不会阻塞,会继续执行
for (int i = 0; i < 60; i++) {
System.out.println("main~~~~" + Thread.currentThread().getName());
Thread.sleep(1000);
}
}
}
class Cat extends Thread {
int times = 0;
@Override
public void run() {
while (true) {
System.out.println("miao~~~~~" + (++times) + "Thread name " + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (times == 80) {
break;
}
}
}
}
public synchronized void start() {
private native void start0();//start()方法调用start0()方法后,该线程不会立即执行,只是该线程变成了可运行状态,是么时候执行有cup调度执行,start0由JVM机实现,实现多线程的start0方法,而不是run()方法。
}
- 实现Runable接口
- 跟适合多个线程共享一个资源的情况,并且避免了多继承的问题
public class Thread02 {
public static void main(String[] args) {
Dog dog = new Dog();
Thread thread = new Thread(dog);
thread.start();
}
}
class Dog implements Runnable {
int count = 0;
@Override
public void run() {
while (true) {
System.out.println("dog dog..." + (++count) + Thread.currentThread().getName());
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (count == 8) {
break;
}
}
}
}
- 实现Callable接口
线程终止
- 在一个线程中设置一个变量,可以再另一个线程中修改此变量,从而终止线程的运行
线程常用方法
setName();//设置线程名
getName();//获取线程名
start();//底层创建新的线程
run();//普通方法,不会创建新的线程
setPriority();//设置优先级
getPriority();//获取优先级
interrupt();//中断线程,并没有真正的结束线程,所以一般中断正在休眠的线程
sleep();//使当前线程进入休眠,(暂停执行)
yield();//线程的礼让,让出CPU让其他线程执行,但礼让时间不确定,所以不一定礼让成功
join();//线程插队,线程一旦插队成功,则肯定先执行完插队成功的线程的所有任务
用户线程和守护线程
- 用户线程
- 工作线程:当线程的执行任务完成或通知方式结束
- 守护线程
- 一般为工作线程服务,当所有用户线程结束,守护线程自动退出,常见的守护线程:垃圾回收机制
public class Thread04 {
public static void main(String[] args) throws InterruptedException {
MyDaemonThread thread = new MyDaemonThread();
thread.setDaemon(true);//设置线程为守护线程,当所有线程退出后,守护线程退出
thread.start();
for (int i = 0; i < 10; i++) {
System.out.println("main main main");
Thread.sleep(1000);
}
}
}
class MyDaemonThread extends Thread {
@Override
public void run() {
while (true) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("demo demo demo");
}
}
}
线程的生命周期
- new:尚未启动的线程
- Runnable:可运行状态(Ready就绪状态,Running运行状态),Runnable状态不一定处于执行,取决于CPU调度
- Terminated:终止状态
- Time Waiting:超时等待状态
- Waiting:等待状态
- Blocked:阻塞状态
线程同步Synchronized
-
线程同步机制
- 在多线程编程中,一些敏感数据不允许被多个线程同时访问,此时就要使用同步访问机制保证数据在同一时刻最多只有一个线程访问,保证数据的完整性
- 线程同步,即当一个线程对内存进行操作室其他线程都不可以对这个内存地址进行操作,直到这个线程完成操作,其他线程才可以对该地址进行操作
-
同步具体方法
- synchronized非公平锁,互斥锁
- 同步代码块synchronized
syschronized(对象){//获取同步对象后,得到对象的锁,错做同一个对象即可 }
- synchronized放在方法声明中表示同步整个方法
public syschronized void sell() {...}//同步方法,这时锁在this对象上
-
同步方法没有使用static修饰的话,默认锁对象为this
-
如果使用static修饰,默认锁对象为 类.class对象
-
必须要求多个线程的锁对象为同一把锁
线程死锁
- 多个线程都占用了对方的锁资源,并且都不愿释放
- 避免同事对多个对象加锁并抢夺锁
public class DeadThread {
public static void main(String[] args) {
DeadLockThread A = new DeadLockThread(true);
DeadLockThread B = new DeadLockThread(false);
A.setName("A");
B.setName("B");
A.start();
B.start();
}
}
class DeadLockThread extends Thread{
static Object o1 = new Object();
static Object o2 = new Object();
boolean flag;
public DeadLockThread(boolean flag) {
this.flag = flag;
}
@Override
public void run() {
if (flag == true) {
synchronized (o1) {
System.out.println(Thread.currentThread().getName() + " 进入1");
synchronized (o2) {
System.out.println(Thread.currentThread().getName() + " 进入2");
}
}
} else {
synchronized (o2) {
System.out.println(Thread.currentThread().getName() + " 进入3");
synchronized (o1) {
System.out.println(Thread.currentThread().getName() + " 进入4");
}
}
}
}
}
释放锁
- 当前线程的同步方法,同步代码块执行结束
- 当前线程在同步代码块,同步方法中遇到break,return
- 当前线程在同步代码块、同步方法中出现了未处理的error或exception,导致异常结束
- 当前线程在同步代码块、同步方法中执行了线程对象的wait()方法,当前线程暂停,并释放锁
不释放锁
- 线程执行同步代码块或同步方法时,程序调用Thread.sleep()、Thread.yeild()方法暂停当前线程的执行,不会释放锁
- 线程执行同步代码块或同步方法,其他线程调用了该线程的suspend()方法;