Java并发编程4

(接上文)

4.8. 关闭线程

4.8.1 进程正常结束

如果一个进程不涉及复杂耗时的逻辑,让它一直执行自动结束即可。

4.8.2 捕获中断信号退出线程

使用前面的interrupt()方法向线程发送中断信号,再通过isInterrupted()/interrupted()捕获。(注意这两个方法的区别)

/**
 * 捕获中断信号方式退出线程
 */
public class ThreadExitDemo01 {
    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(){
            @Override
            public void run() {
                System.out.println("I am running");
                while (!this.isInterrupted()) {
                    // run
                }
                System.out.println("I am exiting");
            }
        };

        t.start();
        TimeUnit.SECONDS.sleep(5);  // 模拟主线程5秒钟后关闭
        System.out.println("main is exiting");
        t.interrupt();  // 向t发送中断信号
    }
}
I am running
main is exiting
I am exiting

Process finished with exit code 0

4.8.3 使用volatile关键字

以下程序也可以达到相同目的。关于volatile关键字后续学习…

/**
 * 声明一个volatile属性成员变量
 */
public class ThreadExitDemo02 {
    public static void main(String[] args) throws InterruptedException {
        TestThread t = new TestThread();

        t.start();
        TimeUnit.SECONDS.sleep(5);  // 模拟主线程5秒钟后关闭
        System.out.println("main is exiting");
        t.interrupt();  // 向t发送中断信号
    }
}

class TestThread extends Thread {
    public volatile boolean closed = false;  // 开关,相当于中断信号的作用

    @Override
    public void run() {
        System.out.println("I am running");
        while (!closed && !this.isInterrupted()) {
            // run
        }
        System.out.println("I am exiting");
    }

    public void close() {
        this.closed = true;
        this.interrupt();
    }
}

4.9. 总结

本节学习了Thread类的获取线程信息、获取当前线程、yield()sleep()join()、进程中断的相关API方法及其作用,最后了解了几种关闭线程的方法。

五、线程安全和数据同步

5.1 synchronized

5.1.1 synchronized的使用

synchronized可以修饰方法使该方法成为同步方法,同一时间只有一个线程能够运行该方法;synchronized也可以将一段代码包住,形成同步块,同一时间只有一个线程能够运行该块代码。

// 同步方法
public synchronized void method {
	// 代码
}

// 同步块
public void method {
	synchronized (o) {
		// code
	}
}

5.1.2 synchronized作用分析

先运行synchronized方法或块的线程会持有锁,将该方法或该段代码锁定,只允许当前线程运行。待此线程运行完成synchronized方法或块时,会释放对该方法或该段代码锁定,其他线程方可竞争锁。竞争到锁的线程重复上述过程。
在这里插入图片描述

5.1.3 synchronized 关键字使用注意

  1. synchronized的锁对象不能为null;
public class Test extends Thread {
	private final Object MUTEX = null;  // 错误
	public void run() {
		while (true) {
			synchronized(MUTEX) {
				// code
			}
		}
	}
}
  1. synchronized作用域太大;
  2. 不同的锁对象企图锁相同的代码块;
public class Test implements Runnable {
	private final Object MUTEX = new Object();
	public void run() {
		while (true) {
			synchronized(MUTEX) {
				// code
			}
		}
	}
	
	public static void main(String[] args) {
		for (int i = 0; i < 5; i++) {
			new Thread(new Test()).start();  // 这里创建的5个线程获得的MUTEX不是同一个对象,无法达到同步的效果。
		}
	}
}
  1. 死锁问题
    在这里插入图片描述
class T1 extends Thread {
	public void run() {
		synchronized("A") {
			TimeUnit.SECOND.sleep(3);
			synchronized("B") {
			  	// codes
			}
		}
	}
}
class T2 extends Thread {
	public void run() {
		synchronized("B") {
			TimeUnit.SECOND.sleep(3);
			synchronized("A") {
			  	// codes
			}
		}
	}
}
public static void main(String[] args) {
	new T1().start();
	new T2().start();   // 死锁
}

使用jstack指令查看线程信息:
在这里插入图片描述

5.2 ThisMonitor和ClassMonitor

5.2.1 ThisMonitor

即以当前对象作为锁。形式可以是:

public class T {
 	public synchronized void method1() {  // 加在非静态方法上
 		// code
 	}
 	public void method2() {
 		synchronized(this) {  // 使用this关键字
 			// code
 		}
 	}
}

5.2.2 ClassMonitor

即以当前类的Class对象作为锁。形式可以是:

public class T {
 	public synchronized static void method1() {  // 加在静态方法上
 		// code
 	}
 	public void method2() {
 		synchronized(T.class) {  // 使用类Class对象
 			// code
 		}
 	}
}

注意: 如果想要都添加了synchronized的方法同时可以被调用,需要其中一个方法使用synchronized块的形式:

public class T {
	public synchronized void method1() {  // 加在非静态方法上
		// code
	}

private final Object MONITOR = new Object();  // 使用另一个对象,避免使用this monitor
	public void method2() {
		synchronized(MONITOR) { 
			// code
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值