java 控制线程启动 java线程调用方法_创建线程


代码如下:分别是继承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...............";
    }
}

线程的生命周期:

java 控制线程启动 java线程调用方法_System_02


从粘了一个图,然后解释一下

说一下这几个状态;

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());
        }
    }

java 控制线程启动 java线程调用方法_System_03


在线程池中使用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。