用户线程是主线程创建的线程
GC线程是为守护线程,主要回收主线程;
线程分为守护线程和非守护线程(即用户线程)。
只要当前JVM实例中尚存在任何一个非守护线程没有结束,守护线程就全部工作;只有当最后一个非守护线程结 束时,守护线程随着 JVM 一同结束工作。 守护线程最典型的应用就是 GC (垃圾回收器)。
现在有T1、T2、T3三个线程,你怎样保证T2在T1执行完后执行,T3在T2执行完后执行
public class JoinThreadDemo02 {
public static void main(String[] args) {
Thread t1 = new Thread(new Runnable() {
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println("t1,i:" + i);
}
}
});
Thread t2 = new Thread(new Runnable() {
public void run() {
try {
t1.join();
} catch (Exception e) {
// TODO: handle exception
}
for (int i = 0; i < 20; i++) {
System.out.println("t2,i:" + i);
}
}
});
Thread t3 = new Thread(new Runnable() {
public void run() {
try {
t2.join();
} catch (Exception e) {
// TODO: handle exception
}
for (int i = 0; i < 20; i++) {
System.out.println("t3,i:" + i);
}
}
});
t1.start();
t2.start();
t3.start();
}
}
多线程分批处理
线程安全
线程安全解决问题
同步保证数据的安全问题
同步函数:用的是this锁
静态同步函数
下面验证静态同步函数使用当前字节码文件作为锁
多线程死锁
多线程三大特性
原子性 可见性 有序性
Java内存模型分为主内存和私有本地内存,产生线程安全
共享内存模型指的就是Java内存模型(简称JMM),JMM决定一个线程对共享变量的写入时,能对另一个线程可见。从抽象的角度来看,JMM定义了线程和主内存之间的抽象关系:线程之间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程以读/写共享变量的副本。本地内存是JMM的一个抽象概念,并不真实存在。它涵盖了缓存,写缓冲区,寄存器以及其他的硬件和编译器优化。
总结:什么是Java内存模型:java内存模型简称jmm,定义了一个线程对另一个线程可见。共享变量存放在主内存中,每个线程都有自己的本地内存,当多个线程同时访问一个数据的时候,可能本地内存没有及时刷新到主内存,所以就会发生线程安全问题。
Volatile:与java内存模型有关
作用:保证线程之间可见,不保证原子性
已经将结果设置为fasle为什么?还一直在运行呢。
原因:线程之间是不可见的,读取的是副本,没有及时读取到主内存结果。
解决办法使用Volatile关键字将解决线程之间可见性, 强制线程每次读取该值的时候都去“主内存”中取值
AtomicInteger是一个提供原子操作的Integer类,通过线程安全的方式操作加减
jdk1.5并发包
程序同步:程序从上向下的有顺序执行
线程同步:保证线程安全,保证数据的原子性。
多线程之间实现通讯
wait()、notify()、notifyAll()是三个定义在Object类里的方法,可以用来控制线程的状态。
这三个方法最终调用的都是jvm级的native方法。随着jvm运行平台的不同可能有些许差异。
如果对象调用了wait方法就会使持有该对象的线程把该对象的控制权交出去,然后处于等待状态。
如果对象调用了notify方法就会通知某个正在等待这个对象的控制权的线程可以继续运行。
如果对象调用了notifyAll方法就会通知所有等待这个对象控制权的线程继续运行。
注意:一定要在线程同步(synchronized)中使用,并且是同一个锁的资源
wait()、notify()同时使用
wait和sleep区别
jdk1.5 lock锁 保证线程安全
Lock 接口与 synchronized 关键字的区别
Lock 接口可以尝试非阻塞地获取锁 当前线程尝试获取锁。如果这一时刻锁没有被其他线程获取到,则成功获取并持有锁。
Lock 接口能被中断地获取锁 与 synchronized 不同,获取到锁的线程能够响应中断,当获取到的锁的线程被中断时,中断异常将会被抛出,同时锁会被释放。
Lock 接口在指定的截止时间之前获取锁,如果截止时间到了依旧无法获取锁,则返回。
class Res {
public String userName;
public String sex;
// true 生产者线程等待,消費可以进行消费 false 生成者可以写, 消费者变为等待
public boolean flag = false;
Lock lock = new ReentrantLock();
}
class Out extends Thread {
Res res;
Condition newCondition;
public Out(Res res,Condition newCondition) {
this.res = res;
this.newCondition=newCondition;
}
@Override
public void run() {
// 写的操作 0 1
int count = 0;
while (true) {
try {
res.lock.lock();
if (res.flag) {
try {
newCondition.await();;// 让当前线程 从运行状态变为休眠状态 并且释放锁的资源
} catch (Exception e) {
// TODO: handle exception
}
}
if (count == 0) {
res.userName = "小红";
res.sex = "女";
} else {
res.userName = "余胜军";
res.sex = "男";
}
// 计算奇数或者偶数公式
count = (count + 1) % 2;
res.flag = true;
// 唤醒
newCondition.signal();
} catch (Exception e) {
// TODO: handle exception
}finally{
res.lock.unlock();
}
}
}
}
class Input extends Thread {
Res res;
Condition newCondition;
public Input(Res res,Condition newCondition) {
this.res = res;
this.newCondition=newCondition;
}
@Override
public void run() {
while (true) {
try {
// 上锁
res.lock.lock();
if (!res.flag) {
try {
newCondition.await();
} catch (Exception e) {
// TODO: handle exception
}
}
System.out.println(res.userName + "," + res.sex);
res.flag = false;
newCondition.signal();
} catch (Exception e) {
// TODO: handle exception
}finally{
// 释放锁
res.lock.unlock();
}
}
}
}
public class OutInputThread {
public static void main(String[] args) {
Res res = new Res();
Condition newCondition = res.lock.newCondition();
Out out = new Out(res,newCondition);
Input input = new Input(res,newCondition);
out.start();
input.start();
}
}
停止线程思路
1. 使用退出标志,使线程正常退出,也就是当run方法完成后线程终止。
2. 使用stop方法强行终止线程(这个方法不推荐使用,因为stop和suspend、resume一样,也可能发生不可预料的结果)。
3. 使用interrupt方法中断线程。
ThreadLocal提供一个线程的局部变量,访问某个线程拥有自己局部变量。