Thread

Thread 的 interrupt 函数

public void Thread.interrupt()				// 中断线程
public boolean Thread.isInterrupted()		// 判断是否被中断
public static boolean Thread.interrupted()	// 判断是否被中断,并清除当前中断状态
// 中断响应方法
Thread t1 = new Thread(() -> {
	while(true) {
		if(Thread.currentThread().isInterrupted()) {
			break;
		}
	}
});

Thread 的 sleep 函数

sleep 的中断异常

有两个线程A、B,当A执行sleep()时,若B调用了A的interrupt(),实质上是设置中断状态,此时A在睡眠,会触发InterruptedException异常,此时需要捕获异常代码段重新设置中断
在这里插入图片描述

Thread t1 = new Thread(() -> {
	while(true) {
		if(Thread.currentThread().isInterrupted()) {
			break;
		}
		// 其他操作
		try {
			Thread.sleep(1000);
		}catch(InterruptedException e) {
			Thread.currentThread().interrupt();
		}
		// 其他操作
	}
});

sleep 时不释放资源

线程调用 sleep ,并不会使该线程释放对象锁,而会在睡眠是一直持有,直到睡醒,并执行其余同步块内容,才释放对象锁
测试代码:

public class Test {
	public static Object u = new Object();
	public static class MyRunnable implements Runnable{
		@Override
		public void run() {
			synchronized (u) {
				System.out.println(Thread.currentThread().getName() + " run");
				try {
					Thread.sleep(1000);
				}catch(InterruptedException e) {
					Thread.currentThread().interrupt();
				}
				System.out.println(Thread.currentThread().getName() + " finish");
			}
		}
	}
	public static void main(String args[]) throws InterruptedException {
		MyRunnable r = new MyRunnable();
		Thread t1 = new Thread(r, "t1");
		Thread t2 = new Thread(r, "t2");
		t1.start();
		t2.start();
	}
}

测试结果:

在这里插入图片描述


Object 的 wait 和 notify 函数

wait 和 notify 要与 关键字 synchronized 配合使用
在这里插入图片描述

wait 会释放资源

执行 wait 的线程会释放对象锁,让其他线程持有,使其他线程能唤醒该线程
测试代码:

public class Test {
	public static Object u = new Object();
	public static class MyRunnable implements Runnable{
		@Override
		public void run() {
			synchronized (u) {
				System.out.println(Thread.currentThread().getName() + " run");
				try {
					u.wait();
				}catch(InterruptedException e) {
					Thread.currentThread().interrupt();
				}
				System.out.println(Thread.currentThread().getName() + " finish");
			}
		}
	}
	public static void main(String args[]) throws InterruptedException {
		MyRunnable r = new MyRunnable();
		Thread t1 = new Thread(r, "t1");
		Thread t2 = new Thread(r, "t2");
		t1.start();
		t2.start();
		Thread.sleep(1000);
		synchronized (u) {
			u.notifyAll();
		}
	}
}

测试结果:
在这里插入图片描述


线程池

常用创建线程池方法

public static ExecutorService newFixedThreadPool(int nThreads);
public static ExecutorService newSingleThreadExecutor();
public static ExecutorService newCachedThreadPool();

它们本质上是通过构造 ThreadPoolExecutor 对象,因 ThreadPoolExecutor 是 ExecutorService 的子孙类
在这里插入图片描述
newFixedThreadPool() 方法 和 newSingleThreadExecutor() 方法用的是 LinkedBlockingQueue< Runnable >() ,而且没有拒绝策略,意味着当最大线程数满的时候,若有新的任务提交,则会放到等待队列,若提交数度 > 处理数度,等待队列不断增长,最后内存占满

ThreadLocal

多线程访问共享变量可能会线程不安全,若每个线程拥有自己的局部变量,那就不会出现并发问题
Demo(SimpleDateFormat.parse()线程不安全 )

static ThreadLocal<SimpleDateFormat> t1 = new ThreadLocal<>();
public static class ParseDate implements Runnable{
	int i = 0;
	public ParseDate(int i) {this.i = i;}
	public void run() {
		try {
			if(t1.get() == null) {
				t1.set(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
			}
			Date t = t1.get().parse("2015-03-29 19:29:" + i % 60);
			System.out.println(i + ":" + t);
		} catch(ParseException e) {
			e.printStackTrace();
		} finally {
			t1.remove();
		}
	}
}

每个 Thread 都有自己的局部变量,它们存放在 threadLocals 中

public class Thread implements Runnable{
	...
	ThreadLocal.ThreadLocalMap threadLocals = null;
	...
}

通过使用 ThreadLocal 的 set() 将要存入的值放入threadLocals 中,当要用的时候使用 get() ,从中获取对应的数据,从而使线程安全

public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        map.set(this, value);
    } else {
        createMap(t, value);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值