线程基础学习

github地址:https://github.com/liujinjin777/liujinjintest.git

讲解流程为:线程状态 -》实现线程的几种方法 -》线程基本方法和关键字 -》问答时刻

线程状态

这里写图片描述
图来自:http://blog.csdn.net/huang_xw/article/details/7316354

新建、准备/就绪、运行、阻塞、死亡
阻塞:1,等待阻塞,运行线程调用wait方法进入等待池【wait和sleep,wait会释放锁】
2,同步阻塞,就绪状态线程准备获取锁的时候,已经有其他线程占领了,这个时候就进入锁池中。
3,其他阻塞,运行线程调用sleep或者join或者io请求,进入阻塞状态。当sleep结束join线程结束io处理完毕,线程重新进入就绪状态。

Thread类源码状态

public enum State {
    NEW,               // 新建
    RUNNABLE,          // 运行
    BLOCKED,           // 锁阻塞           
    WAITING,           // 等待阻塞(不带有超时值)
    TIMED_WAITING,     // 等待阻塞(带有超时值)
    TERMINATED;        // 终止
}

实现线程的三种方法

其实按照原理来分的话是2种,实现runnable或者callable
1.实现runnable接口,实现run方法。

Thread thread = new Thread(Runable runable);
thread.start();

代码实现:把runnable记录成为Thread的成员变量target 。调用run的时候,直接调用

@Override
public void run() {
    if (target != null) {
        target.run();
    }
}

2.继承Thread类,重写run方法。

Thread myThread = new MyThread();
myThread.start();

3.利用callable接口,重写call方法。

public class MyCallable implements Callable {

    private int flag = 0;

    public MyCallable(int flag){
        this.flag = flag;
    }

    public String call() throws Exception{
        if (this.flag == 0){
            System.out.println("call flag = 1");
            return "flag = 0";
        }

        if (this.flag == 1){
            try {
                while (true) {
                    System.out.println("looping.");
                    Thread.sleep(2000);
                }
            } catch (InterruptedException e) {
                System.out.println("Interrupted");
            }
            return "false";
        } else {
            System.out.println("Bad flag value!");
            throw new Exception("Bad flag value!");
        }

    }
}
//-------- 第1种写法,类似重写runable接口
MyCallable task1 = new MyCallable(0);
MyCallable task2 = new MyCallable(2);

FutureTask<MyCallable> oneTask1 = new FutureTask<MyCallable>(task1);
FutureTask<MyCallable> oneTask2 = new FutureTask<MyCallable>(task2);

Thread thread = new Thread(oneTask1);
Thread thread2 = new Thread(oneTask2);

thread.start();
thread2.start();

//-------- 第2种
MyCallable task1 = new MyCallable(0);
MyCallable task2 = new MyCallable(1);
MyCallable task3 = new MyCallable(2);

ExecutorService es = Executors.newFixedThreadPool(3);
try {
    // 提交并执行任务,任务启动时返回了一个Future对象,
    // 如果想得到任务执行的结果或者是异常可对这个Future对象进行操作
    Future future1 = es.submit(task1);
    // 获得第一个任务的结果,如果调用get方法,当前线程会等待任务执行完毕后才往下执行
    System.out.println("task1: " + future1.get());

    Future future2 = es.submit(task2);
    // 等待5秒后,再停止第二个任务。因为第二个任务进行的是无限循环
    Thread.sleep(5000);
    System.out.println("task2 cancel: " + future2.cancel(true));

    // 获取第三个任务的输出,因为执行第三个任务会引起异常
    // 所以下面的语句将引起异常的抛出
    Future future3 = es.submit(task3);
    System.out.println("task3: " + future3.get());
} catch (Exception e){
    System.out.println(e.toString());
}

// 停止任务执行服务
es.shutdownNow();

callable与runable的差别
1,重写call方法和重写run方法
2,可以有返回值
3,可以抛出异常

线程基本方法和关键字

start、sleep、join 、yeild、run、wait、notify、notifyAll、interrupt、synchronized、volatile

start:启动一个线程。会调用run方法。
sleep:睡眠一个线程。睡眠期间不会释放锁。【com.liujinjin.myThread.testSleep】
join:当前线程会等待调用join线程运行后运行。【com.liujinjin.myThread.testJoin】
yeid:让步线程。尽可能(不绝对)让优先级高的执行 。【com.liujinjin.myThread.testYield】
每个线程都有自己的执行级别,范围是1-10,默认为5。通过setPriority方法更改。
run:与start配合使用,如果直接调用和普通方法是一样的。
wait : 等待线程。等待期间释放锁,调用前需要获得调用对象锁。【com.liujinjin.myThread.testWait】
notify : 唤醒线程。与wait方法联合使用,调用前需要获得对象锁。调用后不释放锁。【com.liujinjin.myThread.testnotify2】
notifyAll :与notify类似,唤醒所有wait线程。
interrupt : 不会中断一个线程。而是当线程被阻塞(wait,join,sleep)时,一种停止阻塞的方法。【com.liujinjin.myThread.testInterrupt】


Object:wait、notify、notifyAll
Thread:start、sleep、join 、yeild 、interrupt
Runnale:run
关键字:synchronized、volatile

native修饰:wait、notify、notifyAll、start0、sleep、yeild、interrupt0
非native修饰:join、run
synchronized修饰:start、join
static修饰:sleep

问答

1.什么时候需要考虑线程安全问题?
当使用变量为成员变量的时候。方法内定义的变量无线程问题。
2.线程可以重复启动吗?
不可以,在start的时候会检查线程状态,如果不为0会 throw IllegalThreadStateException。
2.1那么线程池是如何做的?
待调研
3.线程的底层是通过cpu时间分片来实现的,串行化随机分给每个线程时间片。为什么这样会比单线程快?
4.线程的优点和缺点
5.volitle为何不能保证线程安全?
其底层实现原理,在汇编语言加了lock前缀,实现的功能是
1)在处理器中运算的变量改变后,立刻刷回主线程。
2)主线程里的变量被修改之后,失效其他处理器内的变量值。
一个加法操作。
1)从主线程读取变量值到处理器。
2)更改值。
3)刷回主线程。
6.为什么wait、notify、notifyAll等方法放在object类里,而不是thread类里?
1,wait、notify是sychnized修饰的,调用的前提是获取到当前对象的锁,而锁是这个对象本身。如果是放在thread里,每个对象的锁是当前的thread对象,其他线程调用的时候需要先获取到之前wait线程对象锁。不直观,复杂。
2,可以让object类和子类使用成为锁。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值