线程啊是个好东西,但是平时工作很少自己创建线程,所以一些基础的操作可能就不容易记起来,这篇文章常看看有益身心健康
1. 创建
public class TestDeamon {
public static void main(String[] args) {
// lambda 表达式
Thread t1 = new Thread(()->System.out.println("这是一个线程01!"));
Thread t2 = new Thread(()->{
System.out.println("这是一个线程02!");
});
// 匿名内部类
Thread t3 = new Thread(){
@Override
public void run() {
System.out.println("这是一个线程03!");
}
};
// 继承Thread
Thread t4 =new MyThread04();
// 实现Runnable 参数是Runnable
Thread t5 = new Thread(new MyRunnable());
// 时效内
// 启动线程
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
}
}
/**
* 继承Thread
* public class Thread implements Runnable
* thread是实现了Runnable接口
*/
class MyThread04 extends Thread{
@Override
public void run() {
System.out.println("这是一个线程04!");
}
}
/**
* 实现Runnable
*/
class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("这是一个线程05!");
}
}
复制代码
2. 启动
// 启动线程
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
输出:
这是一个线程01!
这是一个线程02!
这是一个线程03!
这是一个线程04!
这是一个线程05!
复制代码
线程启动之后就会执行 run 方法
3. 停止线程/中断
3.1. 线程执行完 自己结束
执行完 for 循环 自动结束
// lambda 表达式
Thread t1 = new Thread(()->{
for (int i = 0; i < 10; i++) {
try{
Thread.sleep(1000);
System.out.println("===");
} catch (Exception e) {
e.printStackTrace();
}
}
});
t1.start();
复制代码
3.2. stop 被废弃了
stop 已经被废弃,stop 太粗暴,不温柔,所以没人喜欢..
// lambda 表达式
Thread t1 = new Thread(()->{
for (;;) {
try{
Thread.sleep(1000);
System.out.println("===");
} catch (Exception e) {
e.printStackTrace();
}
}
});
t1.start();
// 10秒后 停止
Thread.sleep(10000);
// 停止
t1.stop();
复制代码
很容易产生数据不一致 因为某一个事务或者一块代码没执行完的时候 就有可能被干掉
举个例子:
// lambda 表达式
Thread t1 = new Thread(()->{
System.out.println("对象去洗澡了");
try{
System.out.println("钻被窝等着...");
Thread.sleep(10000);
System.out.println("洗白白 开小会");
} catch (Exception e) {
e.printStackTrace();
}
});
t1.start();
// 10秒后 停止
Thread.sleep(5000);
// 停止
t1.stop();
结果:
对象去洗澡了
钻被窝等着...
可以看到哈,你等了半天,还没开始开小会就被打断了 。。
复制代码
3.3 suspend resume 被废弃了
suspend 让线程暂停
resume 让暂停的线程继续执行
suspend 容易产生死锁等问题 如果忘记 resume 或者 resume 异常 那如果 suspend 的线程持有锁的话,就死锁了
public class TestDeamon03 {
// 锁 表示对象
public static Object obj = new Object();
public static void main(String[] args) throws InterruptedException {
// lambda 表达式
Thread t1 = new Thread(()->{
synchronized (obj){
try {
System.out.println("我出去打工了 留对象在家");
Thread.sleep(10000);
System.out.println("我回来了 娶我对象 ");
} catch (Exception e) {
e.printStackTrace();
}
}
});
t1.start();
// 2秒后 暂停
Thread.sleep(2000);
// 暂停
t1.suspend();
Thread.sleep(2000);
// 恢复
resumeObj(t1);
}
// resume 模拟异常
static void resumeObj(Thread t){
int i = 1/0;
t.resume();
}
}
复制代码
你找了个对象,把人家放家里,说打工 1 年回来娶,然后你回家途中找了个别人,一起幸福生活了,你对象在家...
被你占用,你又不通知、不释放
3.4 volatile 结束
volatile(保证内存可见)修饰一个变量 时间可能控制不是很精确 因为 volatile 修改了之后刷新到内存 在另一个线程读取到 还是需要时间的 虽然很快 但是一般的情况 都没什么问题
public class TestDeamon04 {
static volatile boolean flag = true;
public static void main(String[] args) throws InterruptedException {
// lambda 表达式
Thread t1 = new Thread(()->{
int count =0;
// flag == true 循环 flag==false 停止循环 也就结束线程了
while (flag) {
try {
Thread.sleep(1);
count++;
} catch (Exception e){
e.printStackTrace();
}
}
System.out.println("count:"+count);
});
t1.start();
// 1秒后 停止
Thread.sleep(1000);
flag = false;
}
}
多次输出结果:
505、525、507、512
可以看到每次输出结果是不确定的 ,
这种方式只能保证到达某个条件了就停止线程
但是不能控制线程准确点停止
比如你想让一个线程循环100次就停止 很难准确控制
复制代码
3.5 interrupt 结束
也算标志位 但是比 volatile 高级一点 比如 sleep、wait 等操作会被中断
// lambda 表达式
final Thread t1 = new Thread(()->{
int count =0;
//
while (!Thread.interrupted()) {
try {
count++;
} catch (Exception e){
e.printStackTrace();
}
}
System.out.println("count:"+count);
});
t1.start();
// 1秒后 停止
Thread.sleep(1000);
t1.interrupt();
复制代码
中断 sleep 测试:interrupt 会中断 sleep 在异常捕获里边 break 就行了 而标志位 flag 是无法做到的
public class TestDeamon06 {
static volatile boolean flag = true;
public static void main(String[] args) throws InterruptedException {
// lambda 表达式
final Thread t1 = new Thread(()->{
//
while (!Thread.interrupted()) {
try {
Thread.sleep(20000000);
} catch (Exception e){
break;
}
}
System.out.println("interrupted 结束 ");
});
// lambda 表达式
final Thread t2 = new Thread(()->{
while (flag) {
try {
Thread.sleep(20000000);
} catch (Exception e){
break;
}
}
System.out.println("volatile-结束");
});
t1.start();
t2.start();
// 1秒后 停止
Thread.sleep(1000);
t1.interrupt();
flag = false;
}
}
复制代码
总结:
stop 、suspend resume 已废弃
volatile 标志位 无法中断 sleep wait 等操作
interrupt 相当于标志位但是可以中断 sleep wait 等操作 捕获 InterruptedException 异常 进行线程结束
可能还有其他方式 大多数是基于标志位的
欢迎关注公众号:
评论