线程

一、线程的状态

716271-20170320112245721-1831918220.jpg

因为调用sleep()和join()而阻塞的线程,仍然持有锁,待sleep()和join()结束,进入准备就绪状态;

而调用wait()的线程会放弃锁的持有,进而调用notify()唤醒之后,如同没有获取到Synchronized锁的线程一样,继续竞争锁,竞争到锁以后,进入准备就绪状态。

join

t.join()方法阻塞调用此方法的线程阻塞状态,直到线程t完成,此线程再继续(即主线程阻塞,等待t线程优先运行完毕)。

public class JoinTester01 implements Runnable {
 
    private String name;
 
    public JoinTester01(String name) {
    this.name = name;
    }
 
    public void run() {
    System.out.printf("%s begins: %s\n", name, new Date());
    try {
        TimeUnit.SECONDS.sleep(4);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    System.out.printf("%s has finished: %s\n", name, new Date());
    }
 
    public static void main(String[] args) {
    Thread thread1 = new Thread(new JoinTester01("One"));
    Thread thread2 = new Thread(new JoinTester01("Two"));
    thread1.start();
    thread2.start();
    
    try {
        thread1.join();
        thread2.join();
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    
    System.out.println("Main thread is finished");
    }
 
}

20181128210838190.png

如果去除join:

20181128210959261.png

yeild

当前线程从运行状态变为可执行状态,放弃当前cpu的资源,将它让给其他任务。放弃的时间不确定,有可能立刻放弃,也可能过一段时间放弃,有可能刚刚放弃,马上又获得cpu的时间片。

二、Thread,Runnable

区别:

1、Thread也实现了Runnable接口

public class Thread implements Runnable {}

并进行了扩展,除了Runnable的wait、notify方法外,增加了interrupt、isInterrupted、join方法。

2、实现了Runnable的类可以放入线程池。

Thread中的run和start:

run()方法用的是当前线程(主线程)的调用栈,程序还是要顺序执行的;

start()方法的启动是在独立的调动栈中进行的,是真正的多线程。

public class RunAndStart extends Thread{
    @Override
    public void run() {
        try {
            for (int i = 0; i < 5; i++) {
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName() + " " + i);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        RunAndStart thread1 = new RunAndStart();
        RunAndStart thread2 = new RunAndStart();
        thread1.run();
        thread2.run();
    }
}

结果:

main 0
main 1
main 2
main 3
main 4
main 0
main 1
main 2
main 3
main 4
public class RunAndStart extends Thread{
    @Override
    public void run() {
        try {
            for (int i = 0; i < 5; i++) {
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName() + " " + i);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        RunAndStart thread1 = new RunAndStart();
        RunAndStart thread2 = new RunAndStart();
        thread1.start();
        thread2.start();
    }
}

结果:

Thread-1 0
Thread-0 0
Thread-1 1
Thread-0 1
Thread-0 2
Thread-1 2
Thread-1 3
Thread-0 3
Thread-0 4
Thread-1 4

同时,启动实现了Runnable接口的线程的正确方法是:

new Thread(runnable(这是Runnable的一个实例)).start;

而不是直接调用其run()方法。

三、Callable、Future

Callable接口:

public interface Callable<V> {
   
    V call() throws Exception;
}

Future接口:

public interface Future<V> {

    boolean cancel(boolean mayInterruptIfRunning);

    boolean isCancelled();

    boolean isDone();

    V get() throws InterruptedException, ExecutionException;

    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

FutureTask类:

lingpaitong.png

那么如何获取Callable的返回结果呢:

把Callable实例当作参数,生成一个FutureTask的对象,然后把这个对象当作一个Runnable,作为参数另起线程。由于FutureTask实现了Runnable,因此它既可以通过Thread包装来直接执行,也可以提交给ExecuteService来执行。

https://my.oschina.net/u/3572551/blog/1862260/

四、Conditon信号量

线程之间除了同步互斥,还要考虑通信。在Java5之前我们的通信方式为:wait 和 notify。那么Condition的优势是支持多路等待,就是我可以定义多个Condition,每个condition控制线程的一条执行通路,而传统方式只能是一路等待。

Condition对象是需要关联Lock对象的,调用Lock对象的newCondition()对象创建而来,也就是说Condition的使用是需要依赖Lock对象的:

{
        ReentrantLock lock = new ReentrantLock();
        Condition condition = lock.newCondition();
        Thread thread = new Thread(() -> {

            lock.tryLock();
            try {
                System.out.println("wait signal");
                condition.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("got signal");
            lock.unlock();
        });

        Thread thread2 = new Thread(() -> {

            lock.tryLock();
            System.out.println("i got the lock");
            try {
                TimeUnit.SECONDS.sleep(1);
                condition.signal();
                System.out.println("i send a signal");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            lock.unlock();
        });

        thread.start();
        TimeUnit.MILLISECONDS.sleep(10);
        thread2.start();
        TimeUnit.SECONDS.sleep(2);
}

结果:

wait signal
i got the lock
i send a signal
got signal

使用Condition和普通队列实现一个阻塞队列:

public class BQueue {
    private int size=5;
    private Queue<Integer> queue=new LinkedList<Integer>();
    private Lock lock = new ReentrantLock();
    private Condition notFull  = lock.newCondition();
    private Condition notEmpty = lock.newCondition();

    private void poll() {
        lock.lock();
        try {
            while(queue.size() == 0){
                try {
                    System.out.println("队列空,等待数据");
                    notEmpty.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            queue.poll();
            notFull.signal();
            System.out.println(Thread.currentThread().getName()+"从队列取走一个元素,队列剩余"+queue.size()+"个元素");
        } finally{
            lock.unlock();
        }

    }

    private void add() {
        lock.lock();
        try {
            while(queue.size() == size){
                try {
                    System.out.println(Thread.currentThread().getName()+"队列满");
                    notFull.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            queue.add(1);
            notEmpty.signal();
            System.out.println(Thread.currentThread().getName()+"向队列插入一个元素,队列剩余"+queue.size()+"个元素");
        } finally{
            lock.unlock();
        }

    }

    public static void main(String[] args) {
        final BQueue q=new BQueue();
        Runnable t1=new Runnable(){
            public void run() {
                while (true){
                    try {
                        TimeUnit.SECONDS.sleep(1);
                        q.add();
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }

                }

            }
        };
        Runnable t2=new Runnable(){
            public void run() {
                while (true) {
                    try {
                        TimeUnit.SECONDS.sleep(7);
                        q.poll();
                    }catch (InterruptedException e){
                        e.printStackTrace();
                    }
                }
            }
        };
        new Thread(t1).start();
        new Thread(t1).start();
        new Thread(t2).start();
    }
}

结果:

Thread-1向队列插入一个元素,队列剩余1个元素
Thread-0向队列插入一个元素,队列剩余2个元素
Thread-0向队列插入一个元素,队列剩余3个元素
Thread-1向队列插入一个元素,队列剩余4个元素
Thread-0向队列插入一个元素,队列剩余5个元素
Thread-1队列满
Thread-0队列满
Thread-2从队列取走一个元素,队列剩余4个元素
Thread-1向队列插入一个元素,队列剩余5个元素
Thread-1队列满
Thread-2从队列取走一个元素,队列剩余4个元素
Thread-0向队列插入一个元素,队列剩余5个元素
Thread-0队列满

Condition原理:

https://www.jianshu.com/p/58651d446e03

转载于:https://my.oschina.net/u/2286010/blog/3073026

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值