Java复习——多线程

多线程

Thread和Runnable的区别

  1. 一般使用Runnable,因为可以避免单继承的局限性。
  2. Runnable可以更方面的体现数据共享的概念(但不是说Thread类不能实现数据共享)

线程的状态转换

  1. 创建状态:
    创建了一个线程对象后,如Thread thread = new Thread();此时,已经有了相应的内存空间和资源,但是还处于不可运行的状态

  2. 就绪状态:
    调用线程的start()启动线程,进入线程队列排队,具备了运行条件,等待CPU的执行时间片

  3. 运行状态:
    获得CPU时间片,并调用了run()。

  4. 阻塞状态:
    运行状态中的线程,被人为挂起或者调用了sleep()、wait()、suspend(),线程进入阻塞状态。将让出CPU执行权并暂时中止自己的执行。阻塞时,线程不能进入排队队列,只有当引起阻塞的原因消除后,线程才可以进入就绪状态。

  5. 终止状态:
    调用stop()或者run()执行结束后,处于该状态。处于该状态的线程不再具有继续运行的能力。


public class Temp {
    private int mCurrentNum;
    private final int MAX = 10;

    public static void main(String[] args) {
        Producer producer = new Producer();
        new Thread(producer,"Thread111").start();
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        producer.run();
//        输出:
//        Thread111
//        main
    }


}
class Producer implements Runnable {

    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}

死锁

所谓死锁,就是两个线程都在等待彼此的锁,造成了程序的停滞状态。一般是过多的同步导致的。生活中的例子:小孩A想要小孩B的玩具,小孩B想要小孩A的连环画,A对B说:“你把玩具给我,我就把连环画给你”,B不服气道:“你先把你的连环画给我,我才给你玩具”,就这样,双方都在等待在对方的答复(锁),僵持不下:

public class Temp {

    public static void main(String[] args) {
        DeadLock lock1 = new DeadLock();// 因为两个锁对象都是static,所以可体现共享
        DeadLock lock2 = new DeadLock();
        lock1.flag = true;
        new Thread(lock1).start();
        lock2.flag =false;
        new Thread(lock2).start();
    }


}

class DeadLock implements Runnable{
    private static A a = new A();// 为了让其唯一,置为static
    private static B b = new B();// 为了让其唯一,置为static
    public boolean flag;//用于判断谁先执行
    @Override
    public void run() {
        if (flag) {
            synchronized (a){
                a.say();
                try {
                    Thread.sleep(500);// 为了更好的模拟效果,此处休眠500ms
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (b) {
                    a.get();
                }
            }
        } else {
            synchronized (b){
                b.say();
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (a){
                    b.get();
                }
            }
        }
    }
}

class A{
    public void say(){
        System.out.println("A对B说:“你把玩具给我,我就把连环画给你”");
    }

    public void get(){
        System.out.println("A得到玩具");
    }
}

class B{
    public void say(){
        System.out.println("B对A说:“你先把你的连环画给我,我才给你玩具”");
    }

    public void get(){
        System.out.println("B得到连环画");
    }
}

sleep()和wait()区别

sleep()是Thread的静态方法,导致线程以指定时间暂停执行,把CPU执行权让给其他线程,但是监控状态依然保持,到时后,会自动恢复。并且不释放对象锁。

wait()用在同步块或者同步方法内,Object的方法,表示线程等待,让出同步的锁,并进入等待此对象锁的等待锁定池,只有针对此锁的对象发出notify()或者notifyAll()后,才有机会继续执行。释放锁。

生产者消费者问题

public class Temp {
    private int mCurrentNum;
    private final int MAX = 10;

    public static void main(String[] args) {
        Temp temp = new Temp();
        new Thread(temp.new Producer()).start();
        new Thread(temp.new Consumer()).start();
        new Thread(temp.new Producer()).start();
        new Thread(temp.new Consumer()).start();
        new Thread(temp.new Producer()).start();
        new Thread(temp.new Consumer()).start();
        new Thread(temp.new Producer()).start();
        new Thread(temp.new Consumer()).start();
    }

    public class Producer implements Runnable {

        @Override
        public void run() {
            for (int i = 0; i < MAX; i++) {
                synchronized (Temp.this) {
                    while (mCurrentNum == MAX) {// 缓存区已满,停止生产
                        try {
                            Temp.this.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    mCurrentNum++;
                    System.out.println("生产者"+Thread.currentThread().getName()+"生产,产品总数为:"+mCurrentNum+" 个物品");
                    Temp.this.notifyAll();
                }
            }
        }
    }

    public class Consumer implements Runnable {

        @Override
        public void run() {
            for (int i = 0; i < MAX; i++) {
                synchronized (Temp.this) {
                    while (mCurrentNum == 0) {// 缓存区没有数据,停止消费
                        try {
                            Temp.this.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    mCurrentNum--;
                    System.out.println("消费者"+Thread.currentThread().getName()+"消费,剩余产品总数为:"+mCurrentNum+" 个物品");
                    Temp.this.notifyAll();
                }
            }
        }
    }
}

生产者消费者存在的问题:

  1. 设置的数据错位了,可依靠同步解决
  2. 数据会重复取出和重复设置,依靠wait()、notify()机制解决

操作流程如下:

public class Temp {

    public static void main(String[] args) {
        Message message = new Message();
        new Thread(new Producer(message)).start();
        new Thread(new Consumer(message)).start();
    }
}

class Message{
    private String title;
    private String content;
    private boolean flag = true;// ture:表示可以生产,但不能取走;false相反
    public synchronized void set(String title,String content){
        if (!flag) {//已经生产过了,不生产
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.title = title;
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.content = content;
        this.flag = false;// 生产完成,修改标志位
        notifyAll();// 通知消费者,取走
    }

    public synchronized void get(){
        if (flag) {//未生产,不取走
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(this.title+"-->"+this.content);
        this.flag = true;
        notifyAll();
    }
}

class Producer implements Runnable {
    private Message msg = null;
    public Producer(Message msg){
        this.msg= msg;
    }
    @Override
    public void run() {
        for (int i = 0;i < 50;i++){
            if (i % 2 == 0) {
                this.msg.set("aaa", "111");
            } else {
                this.msg.set("bbb","222");
            }
        }
    }
}

class Consumer implements Runnable{
    private Message msg = null;
    public Consumer(Message msg){
        this.msg = msg;
    }
    @Override
    public void run() {
        for (int i = 0;i < 50 ; i++){
            this.msg.get();
        }
    }
}

你可能感兴趣的:(Java,Java复习)