每个线程都有自己的状态,上下文,记账信息等辅助调度信息=》有一个对应的PCB,每个线程都有自己的调用栈。
同时也得掌握我上篇博客写的五种创建线程的方法。
并且新的线程和旧的线程之间是并发关系,只有显示调用start方法,才能真正在内核中创建线程。
Thread中的run和start之间的区别:
run:没有创建新的线程,输出语句实在原线程中执行的。
start:这是要创建一个新的线程。
创建线程
创建线程方法:
1.可以通过显示继承Thread类方式实现
2.也可以通过匿名内部类方式继承Thread类
3.创建一个类,实现Runnable接口,然后把这个Runnable的实例关联到Thread实例上。
4.也可以使用内名内部类去重写runnable里的run方法来创建线程。
5.也可以使用lambda表达式
线程的构造方法
Thread() 创建线程对象
Thread(Runnable target) 使用 Runnable 对象创建线程对象
Thread(String name) 创建线程对象,并命名
Thread(Runnable target, String name) 使用 Runnable 对象创建线程对象,并命名
【了解】Thread(ThreadGroup group,
Runnable target)
线程可以被用来分组管理,分好的组即使线程组,这个目前我们了解即可
线程的几个常见属性
属性 获取方法
ID getId()
名称 getName()
状态 getState()
优先级 getPriority()
是否后台线程 isDaemon()
是否存活 isAlive()
是否被中断 isInterrupted()
ID 是线程的唯一标识,不同线
中断线程
线程结束有两个情况:
1、已经把任务执行完
public class ThreadDemo4 {
private static boolean isQuit = false;
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread() {
@Override
public void run() {
while (!isQuit) {
System.out.println("正在转账");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("转账结束");
}
};
t.start();
Thread.sleep(5000);
System.out.println("对方是内鬼终止交易");
isQuit = true;
}
}
2、任务执行了一半,被强制结束(调用线程的Interrupt方法)
public class ThreadDemo5 {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread() {
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("别管我忙着转账");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
}
System.out.println("转账结束");
}
};
t.start();
Thread.sleep(5000);
System.out.println("终止交易");
t.interrupt();
}
对于新线程来说,run结束,线程就结束啦
对于主线程,main方法执行完,主线程就结束了
清除中断标记
1 Thread.interrupted() 判断当前线程的中断标志被设置,清除中断标志
public class ThreadDemo6 {
public static void main(String[] args) {
Thread t = new Thread() {
@Override
public void run() {
for(int i = 0;i<10;i++) {
System.out.println(Thread.interrupted());
}
}
};
t.start();
t.interrupt();
}
}
代码结果
true
false
false
false
false
false
false
false
false
false
2 Thread.currentThread().isInterrupted() 判断指定线程的中断标志被设置,不清除中断标志
public class ThreadDemo6 {
public static void main(String[] args) {
Thread t = new Thread() {
@Override
public void run() {
for(int i = 0;i<10;i++) {
System.out.println(Thread.currentThread().isInterrupted());
}
}
};
t.start();
t.interrupt();
}
}
代码结果
true
true
true
true
true
true
true
true
true
true
线程等待
线程之间是并发执行的,谁也不知道是谁先执行的
我们可以控制让某个线程先结束。
join:会阻塞线程,直到某个线程结束
public class ThreadDemo8 {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread() {
@Override
public void run() {
for(int i = 0;i<10;i++) {
System.out.println("我是线程1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread t2 = new Thread() {
@Override
public void run() {
for(int i = 0;i<10;i++) {
System.out.println("我是线程2");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
t1.start();
t1.join();
t2.start();
t2.join();
}
}
我是线程1
我是线程1
我是线程1
我是线程1
我是线程1
我是线程1
我是线程1
我是线程1
我是线程1
我是线程1
我是线程2
我是线程2
我是线程2
我是线程2
我是线程2
我是线程2
我是线程2
我是线程2
我是线程2
我是线程2
线程状态
就绪状态:当前线程已经在CPU上准备好了,但还没开始执行
阻塞状态:当前线程停下来了,不会继续执行到CPU上执行
运行状态:在CPU上执行
线程安全问题
线程不安全:多线程并发执行某个代码,产生了逻辑上的错误,就是线程不安全
原因:
1.线程是抢占式执行的
2.自增操作不是原子的**(可以通过给自增加锁来解决)**
3.多个线程尝试修改同一个变量
4.内存可见性导致线程安全问题
5.指令重排序
线程安全:没有逻辑错误,安全
锁的特点:
互斥的,同一时刻只有一个线程能获取到锁
其他线程如果也尝试获取锁,就会发生阻塞等待,一直到刚才的线程释放锁,剩下的线程在重新竞争锁。
锁的基本操作:
加锁:lock
解锁:unlock
Java中使用锁,要借助关键字:synchronized
(加锁解锁都有这个关键字来执行)
把这个关键字加在方法前,实际就是针对某个对象进行加锁的,这个锁可以理解为对象里的一个标记位。
加在普通方法时,表示锁的this
加在类对象前:表示锁当前类的类对象