代码如下:分别是继承Thread,实现Runable,,事项Callable。
此时运行代码是主线程里分别在跑三个子线程。
package com.cloud.test;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println(Thread.currentThread().getName()+":running.....");
//调用线程1
MyThread thread=new MyThread();
thread.start();
//调用线程2 (并不能以线程的方式启动,实际上只是创建了一个任务,需要启动一个线程来去执行它)
Task task=new Task();
new Thread(task).start();
//调用线程3
Task1 task1=new Task1();
FutureTask<String> futureTask=new FutureTask<>(task1);
Thread thread1=new Thread(futureTask);
thread1.start();
String s = futureTask.get();
System.out.println(s);
}
}
//创建线程方式1,继承Thread类,重写run方法
class MyThread extends Thread{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":running.....");
}
}
//创建线程方式2,实现Run类,重写run方法
class Task implements Runnable{
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+":running.....");
}
}
//创建线程方式3,实现Callable类,重写call方法
class Task1 implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println(Thread.currentThread().getName()+":running.....");
return "down...............";
}
}
线程的生命周期:
从粘了一个图,然后解释一下
说一下这几个状态;
new: 创建线程对象。
runnable: 线程就绪。
blocked: 慢于其它线程获得锁,被其它线程先获得执行权,进入blocked状态,直到锁被释放,该线程从新进入runnable状态,继续抢锁。
waiting: 当线程调用wait或者join时,进入waiting,唤醒后进入runnable状态。
timed waiting: 当线程进入sleep(time),wait(time)时进入timed waiting状态。
running: 获取执行权的正在运行的线程状态。
terminated: 执行结束,进入该状态。
主线程睡眠会影响子线程吗???
不会。
各个线程之间的运行时相互独立的,只按照本身的时间线来走,不受别的线程的影响。主线程休眠与子线程无关。主线程只是人为的称呼,为了方便描述所使用的称呼,各个线程是并行存在的,相互独立运行。
sleep和wait区别
1、所属的类不同:sleep是Thread的静态类方法,谁调用的谁去睡觉,即使在a线程里调用了b的sleep方法,实际上还是a去睡觉,要让b线程睡觉要在b的代码中调用sleep。
2、对锁资源的处理方式:sleep不让出系统资源;wait是进入线程等待池等待,出让系统资源,其他线程可以占用CPU。
3、一般wait不会加时间限制,因为如果wait线程的运行资源不够,再出来也没用,要等待其他线程调用notify/notifyAll唤醒等待池中的所有线程,才会进入就绪队列等待OS分配系统资源。sleep(milliseconds)可以用时间指定使它自动唤醒过来,如果时间不到只能调用interrupt()强行打断。
4、sleep必须捕获异常,而wait,notify和notifyAll不需要捕获异常。
5、使用范围,sleep可以使用在任何范围,wait只能使用在同步方法和同步代码块。
ThreadLocal
是线程本地存储,在每个线程中都创建了一个 ThreadLocalMap 对象,每个线程可以访问自己内部 ThreadLocalMap 对象内的 value。也就是可以为每个线程创建自己的副本,存储的数据只能供所存储的线程所使用。
如下代码示例为启动两个线程,使用ThreadLocal保存不同数据,证明如此:
保存是将当前执行线程作为KEY,保存的数据作为VALUE,存进ThreadLocalMap里。
static ThreadLocal threadlocal = new ThreadLocal();
public static void main(String[] args) {
Task task = new Task();
new Thread(task).start();
new Thread(task).start();
}
static class Task implements Runnable {
@Override
public void run() {
if (threadlocal.get() == null) {
threadlocal.set(System.currentTimeMillis());
}
System.out.println(Thread.currentThread().getName() + "------>" + threadlocal.get());
}
}
在线程池中使用ThreadLocal为什么会导致内存泄漏???
在线程池中线程的存活时间太长,往往都是和程序同生共死的,这样 Thread 持有的 ThreadLocalMap 一直都不会被回收,再加上 ThreadLocalMap 中的 Entry 对 ThreadLocal 是弱引用(WeakReference),所以只要 ThreadLocal 结束了自己的生命周期是可以被回收掉的。Entry 中的 Value 是被 Entry 强引用的,即便 value 的生命周期结束了,value 也是无法被回收的,导致内存泄露。
线程池中,如何正确使用 ThreadLocal?
在 finally 代码块中手动清理 ThreadLocal 中的 value,调用 ThreadLocal 的 remove()方法。
ThreadLocal使用场景
UserService去调用UserDao和LogDao,那么这通过一个业务里不能开启两个Connection,所以在这个线程里将Connection存储在ThreadLocal里,当调用LogDao的时候也用这个Connection。