线程启动的方法
start和run方法的区别
1、run属于普通方法,start属于线程启动的方法
2、run方法可以执行多次,而start方法只能执行一次
线程中断
1、使用全局自定义的变量来终止线程
- 终止的方法比较温柔,在拿到终止指令后,需要执行完当前的指令之后才会终止线程
package Thread;
/**
* 使用全局自定义变量来终止线程
* */
public class ThreadDemo10 {
// 全局自定义变量
private static boolean flag = false;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
while(!flag){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("转账中....");
}
System.out.println("终止转账-----");
}
});
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(310);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 改变变量的状态来终止线程的执行
System.out.println("停止交易....");
flag = true;
}
});
t2.start();
t1.join();
t2.join();
}
}
输出为:
转账中....
转账中....
转账中....
停止交易....
转账中....
终止转账-----
2、使用线程提供的终止方法interrupt来终止线程
- 使用全局自定义标识终止线程执行的时候比较温柔,当它收到了终止指令之后,会把当前手头的任务执行完再终止;使用interrupt,在收到终止指令之后会立马结束执行
package Thread;
/**
* 使用 interrupt 来终止线程
* */
public class ThreadDemo11 {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
while(!Thread.interrupted()){ // 判断线程的终止状态
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
break;
}
System.out.println("转账中....");
}
System.out.println("终止转账-----");
}
});
t1.start();
Thread.sleep(310);
// 终止线程
System.out.println("停止交易");
t1.interrupt(); // 终止线程
}
}
输出:
转账中....
转账中....
转账中....
停止交易
终止转账-----
java.lang.InterruptedException: sleep interrupted
at java.lang.Thread.sleep(Native Method)
at Thread.ThreadDemo11$1.run(ThreadDemo11.java:16)
at java.lang.Thread.run(Thread.java:748)
Process finished with exit code 0
interrupted()
和isInterrupted()
的区别:前者是全局,需要复位,后者是私有的,不需要复位。
3、使用线程提供的方法 stop 来终止线程(终止线程时不会释放线程中的资源,该方法不推荐使用)
线程的状态
NEW ——> 新建状态:没有调用线程start()之前的状态
RUNNABLE ——> 运行状态(Running 执行中,Ready就绪)
BLOCK ——> 阻塞状态
WAITING ——> 等待,没有明确结束时间
TIMED_WAITING ——> 超时等待状态,有明确的超时等待结束时间,比如sleep(xxx)
TERMINATED ——> 终止状态
多线程的线程安全问题
- 在单线程,线程安全的情况下:
package Thread;
public class ThreadDemo12 {
static class Counter{
// 定义的私有变量
private int num = 0;
// 任务执行次数
private final int maxSize = 10_0000;
// num++;
public void incrment(){
for (int i = 0; i < maxSize; i++) {
num++;
}
}
// num--;
public void decrment(){
for (int i = 0; i < maxSize; i++) {
num--;
}
}
public int getNum(){
return num;
}
public static void main(String[] args) {
Counter counter = new Counter();
counter.incrment();
counter.decrment();
System.out.println("最终结果:"+counter.getNum());
}
}
}
此时为稳定输出0
- 修改为多线程,线程不安全的情况
package Thread;
public class ThreadDemo13 {
static class Counter{
// 定义的私有变量
private int num = 0;
// 任务执行次数
private final int maxSize = 10_0000;
// num++;
public void incrment(){
for (int i = 0; i < maxSize; i++) {
num++;
}
}
// num--;
public void decrment(){
for (int i = 0; i < maxSize; i++) {
num--;
}
}
public int getNum(){
return num;
}
public static void main(String[] args) throws InterruptedException {
Counter counter = new Counter();
Thread t1 = new Thread(() -> {
counter.incrment();
});
t1.start();
Thread t2 = new Thread(() ->{
counter.decrment();
});
t2.start();
t1.join();
t2.join();
counter.incrment();
counter.decrment();
System.out.println("最终结果:"+counter.getNum());
}
}
}
此时,每次输出的结果都不一样,但一般都不为零,这种情况就叫做线程不安全
- 线程不安全: 在多线程执行中,程序的执行结果和预期不相符,就叫做线程不安全
为什么会导致线程不安全?
1、CPU抢占执行
2、非原子性(++,–都是非原子性操作)
3、编译器优化
- 编译器在单线程下没有问题,可以提升程序的执行效率,但是在多线程下就会出现混乱,从而导致线程不安全的问题
4、(内存)不可见性 - 一个变量在一个线程中修改了,但是另一个线程没有看到这个修改
5、多个线程修个了同一个变量