本文系统介绍了Java线程的重命名、属性获取(如ID、名称、状态、优先级)、生命周期及线程安全问题。通过实例演示线程创建、启动、中断、join等待与sleep休眠机制,重点分析多线程并发导致的共享变量竞争(如a++非原子操作),并提出使用join实现串行执行以保障结果正确性,强调线程同步的重要性。
如何查看线程的进度
线程重命名
//线程对象的重命名
public class thread00 {
public static void main(String[] args) {
Thread n=new Thread(()->{
while (true) {
System.out.println("hello");
}
},"zhang3");
n.start();
}
// 使用Runable对象创建线程对象 并命名
public class thread00 implements Runnable{ @Override public void run() { while (true) { System.out.println("hello"); } } public static void main(String[] args) { thread00 n=new thread00(); Thread m=new Thread(n,"王"); m.start(); } }如果线程没有重命名 则 自动命名Thread0 Thread1 依次往下线程命名
线程的属性怎么获取
ID getid()
获取当前的线程的身份标识pid
名称 getName()
获取当前的线程名字
状态 getState()
获取当前线程的状态
状态分为 前台线程和后台线程
前台线程不重要不影响整个线程的结束 当主要线程结束时 前台线程也随之结束
后台线程是影响整个线程的进程 当后台进程结束时 前台线程也随之结束
优先级 获取当前线程的优先级 getPriorty()
线程的生命周期
线程创建的对象与操作系统中创建的对象是一一对应的但是生命周期不一定随函数的销毁而结束
如果大于3还能打印线程属于线程的随机调用
public class thread00 { public static void main(String[] args) throws InterruptedException { Thread n=new Thread(()->{ for (int i = 0; i < 3; i++) { System.out.println("a"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } }); n.start(); for (int i = 0; i < 3; i++) { System.out.println(n.isAlive()); Thread.sleep(1000); } System.out.println(n.isAlive()); //最后打印存活 } }public class thread00 { public static void main(String[] args) { Boolean a=false; Thread a1=new Thread(()->{ while (!a){ System.out.println("hello"); a=true; try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("a1方法结束"); } }); a1.start(); a=false; } }为什么会变量捕获这样?
a实际为局部变量随生命周期随方法的创建而创建 销毁而销毁 当我们启动线程时 由于线程可以控制时间 有可能函数由创建到销毁完了 线程才刚刚启动
局部变量只是把他的值复制给方法使用 无法像对象给引用 在栈中
局部变量在lambda表达式中会引起“变量捕获” 终止方法的执行
怎么办?
在java引入成员变量引用 通过匿名对象的内部类访问外部类的方式 但是c++中不可以
对象的引用是GC回收 不会随方法的销毁而消失
public class thread00 {
private static Boolean a=false;
//定义的成员变量
public static void main(String[] args) {
Thread a1=new Thread(()->{
while (!a){
System.out.println("hello");
a=true;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("a1方法结束");
}
});
a1.start();
}
}
interrupted引发问题?
public class thread00 {
public static void main(String[] args) {
Thread a=new Thread(()->{
//获取当前的线程对象Thread.currentThread()
while (Thread.currentThread().isInterrupted()){
System.out.println("wen");
Thread.interrupted();
}
});
a.start();
}
}
当启动interrupted标记自动变为false 会触发sleep异常导致中断
解决方法
1通过跳出循环来应对唤醒sleep的异常 让程序更多可执行性
public class thread00 { public static void main(String[] args) throws InterruptedException { Thread a=new Thread(()->{ while (!Thread.currentThread().isInterrupted()){ System.out.println("wen"); try { Thread.sleep(1000); } catch (InterruptedException e) { System.out.println("sleep被唤醒"); // throw new RuntimeException(e); System.out.println("退出中断"); break; } } }); a.start(); //留出更多时间来打印 Thread.sleep(1000); a.interrupt(); } }2通过重新来更改标记位置来应对异常
public class thread00 { public static void main(String[] args) throws InterruptedException { Thread a=new Thread(()->{ while (!Thread.currentThread().isInterrupted()){ System.out.println("wen"); try { Thread.sleep(1000); } catch (InterruptedException e) { System.out.println("sleep被唤醒"); Thread.currentThread().interrupt(); // throw new RuntimeException(e); System.out.println("退出中断"); } } }); a.start(); Thread.sleep(1000); a.interrupt(); } }jion
jion是让线程等待 让别的线程等该线程执行完再运行
jion()
//先执行完子线程再执行main方法
public class thread00 { public static void main(String[] args) throws InterruptedException { Thread a = new Thread(() -> { System.out.println("开始等待"); System.out.println("你好"); System.out.println("结束等待"); }); a.start(); a.join(); Thread.sleep(1000); System.out.println("main执行"); System.out.println("hello"); } }jion(最长等待时间)
public class thread00 { public static void main(String[] args) throws InterruptedException { Thread a = new Thread(() -> { System.out.println("开始等待"); try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("你好"); System.out.println("结束等待"); }); a.start(); a.join(200); System.out.println("main执行"); System.out.println("hello"); } }sleep(0)
让该线程主动放弃当前的CPU
public class thread00 { public static void main(String[] args) throws InterruptedException { Thread a = new Thread(() -> { try { Thread.sleep(0); } catch (InterruptedException e) { throw new RuntimeException(e); } System.out.println("你好我是zhang三"); }); System.out.println("想你"); } }多线程安全问题
并发执行
public class thread00 { public static int a1=0; public static void main(String[] args) throws InterruptedException { Thread a = new Thread(() -> { for (int i = 0; i < 5000; i++) { a1++; } }); Thread a2 = new Thread(() -> { for (int i = 0; i < 5000; i++) { a1++; } }); a.start(); a2.start(); a.join(); a2.join(); System.out.println(a1); } }线程安全引发原因
//想这种并行执行 无论是a先执行完还是a2先执行完 其结果是<10000 偶尔=10000
a++指令在计算机中执行3条指令
1把内存的值加载到cpu寄存器
2cpu寄存器进行++
3把寄存器的值返回给内存
由于cpu的调度是随机 可能执行到一条指令没有完整的执行完就切换到下一条指令 ++操作的值没有返回 造成重复操作 <10000
所以要等3条指令完全执行完才可以进行下一步
采取串行执行
解决串行执行
public class thread00 { public static int a1=0; public static void main(String[] args) throws InterruptedException { Thread a = new Thread(() -> { for (int i = 0; i < 5000; i++) { a1++; } }); Thread a2 = new Thread(() -> { for (int i = 0; i < 5000; i++) { a1++; } }); a.start(); a.join(); a2.start(); a2.join(); System.out.println(a1); } }