java多线程一 基本实现方法、消费者生产者队列、死锁

1.基本概念图

java多线程一 基本实现方法、消费者生产者队列、死锁_第1张图片
四个状态、start 代表被创建、run表示正在运行、阻塞(在干别的事情去了,可以把资源空出来给别人用)、死亡。
核心思想是提高cpu的使用率,你干别的事去了我来利用cpu啊,难点是同步,同时访问数据,一个厕所只有一个坑,俩个人一起上是不文明的。
参考:http://blog.csdn.net/zjwcdd/article/details/51517096

2.基本使用方法

俩种常用使用方法,一个是集成Thread类,一种是实现Runnable接口,因为java有单继承的限制,而接口Runnable可以重复实现多次,还可以利用线程池,推荐接口实现方法:

1.继承方法

class JavaThread extends Thread{
    private String name;
    public JavaThread(String name) {
        this.name=name;
    }
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(name + "运行  :  " + i);
            try {
                sleep((int) Math.random() * 10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}
 class Main {

    public static void main(String[] args) {
        JavaThread mTh1=new JavaThread("A");
        JavaThread mTh2=new JavaThread("B");
        mTh1.start();
        mTh2.start();

    }

}

输出

B运行  :  0
A运行  :  0#可以发现A也可以抢cpu用
B运行  :  1
A运行  :  1
B运行  :  2
A运行  :  2
B运行  :  3
A运行  :  3
B运行  :  4
A运行  :  4

2.实现Runable接口

class JavaThread implements Runnable{
    private String name;

    public JavaThread(String name) {
        this.name=name;
    }

    @Override//表示实现接口的时候重载了
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(name + "运行  :  " + i);
            try {
                Thread.sleep((int) Math.random() * 10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

}
class Main {

    public static void main(String[] args) {
        new Thread(new JavaThread("C")).start();
        new Thread(new JavaThread("D")).start();
    }

}

输出

C运行  :  0
D运行  :  0#可以发现D也在抢C的资源
C运行  :  1
D运行  :  1
C运行  :  2
D运行  :  2
C运行  :  3
D运行  :  3
C运行  :  4
D运行  :  4

另外提一点join,主进程做完了想关闭程序,你新建的子进程没干完事也也也也也也直接退出的话会出问题的,join是主进程等你一起退出,这个第一次用的时候坑了我好久。
参考:java多线程吐血整理http://blog.csdn.net/evankaka/article/details/44153709

3.生产者消费者模式

优点:利用很多个生产者(线程)去生产东西,利用很多个消费者(也是线程)去消费生产的东西,好处是利用多线程来处理,省时间。注意 生产者生产东西的总数有个限制,超过就暂时不生产,等消费者消费完,不然会通货膨胀。消费者有东西就消费,没东西就等待。
难点:生产者和消费者之间的数据的同步的问题(一个文件只能同时让一个人在修改,一个厕所只能一个人同时在用)
模式图:
这里写图片描述
参考:https://www.cnblogs.com/chentingk/p/6497107.html
实现也有很多种方式:
可以参考这个:
生产者/消费者问题的多种Java实现方式http://blog.csdn.net/monkey_d_meng/article/details/6251879
这里举出另外一种:



import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

/**
 * 多线程模拟实现生产者/消费者模型
 *
 * @author 林计钦
 * @version 1.0 2013-7-25 下午05:23:11
 */
public class ProducerConsumer {
    /**
     *
     * 定义装苹果的篮子
     *
     */
    public class Basket {
        // 篮子,能够容纳3个苹果
        BlockingQueue basket = new LinkedBlockingQueue(3);

        // 生产苹果,放入篮子
        public void produce() throws InterruptedException {
            // put方法放入一个苹果,若basket满了,等到basket有位置
            basket.put("An apple");
        }

        // 消费苹果,从篮子中取走
        public String consume() throws InterruptedException {
            // take方法取出一个苹果,若basket为空,等到basket有苹果为止(获取并移除此队列的头部)
            return basket.take();
        }
    }

    // 定义苹果生产者
    class Producer implements Runnable {
        private String instance;
        private Basket basket;

        public Producer(String instance, Basket basket) {
            this.instance = instance;
            this.basket = basket;
        }

        public void run() {
            try {
                while (true) {
                    // 生产苹果
                    System.out.println("生产者准备生产苹果:" + instance);
                    basket.produce();
                    System.out.println("!生产者生产苹果完毕:" + instance);
                    // 休眠300ms
                    Thread.sleep(300);
                }
            } catch (InterruptedException ex) {
                System.out.println("Producer Interrupted");
            }
        }
    }

    // 定义苹果消费者
    class Consumer implements Runnable {
        private String instance;
        private Basket basket;

        public Consumer(String instance, Basket basket) {
            this.instance = instance;
            this.basket = basket;
        }

        public void run() {
            try {
                while (true) {
                    // 消费苹果
                    System.out.println("消费者准备消费苹果:" + instance);
                    System.out.println(basket.consume());
                    System.out.println("!消费者消费苹果完毕:" + instance);
                    // 休眠1000ms
                    Thread.sleep(1000);
                }
            } catch (InterruptedException ex) {
                System.out.println("Consumer Interrupted");
            }
        }
    }

    public static void main(String[] args) {
        ProducerConsumer test = new ProducerConsumer();

        // 建立一个装苹果的篮子
        Basket basket = test.new Basket();

        ExecutorService service = Executors.newCachedThreadPool();
        Producer producer = test.new Producer("生产者001", basket);
        Producer producer2 = test.new Producer("生产者002", basket);
        Consumer consumer = test.new Consumer("消费者001", basket);
        service.submit(producer);
        service.submit(producer2);
        service.submit(consumer);
        // 程序运行5s后,所有任务停止
//        try {
//            Thread.sleep(1000 * 5);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }
//        service.shutdownNow();
    }

}

输出:

生产者准备生产苹果:生产者002
消费者准备消费苹果:消费者001
生产者准备生产苹果:生产者001
!生产者生产苹果完毕:生产者002
!生产者生产苹果完毕:生产者001
An apple
!消费者消费苹果完毕:消费者001
生产者准备生产苹果:生产者001
!生产者生产苹果完毕:生产者001

参考:https://www.cnblogs.com/linjiqin/archive/2013/05/30/3108188.html

4.死锁

锁,同步是解决多线程下保证只有一个线程在处理这个文件的基本方式,我锁住了,别人就不能访问了,直到我不需要了,你才能访问它,上面中的线程安全的队列就是利用这个原理实现的,死锁就是A在等B某个访问结束,B也在等A某个访问结束,俩个都在等,一直等,这样就出现问题了。
总感觉会出现这个问题是因为计算机太傻比了,访问的时候给文件加个锁,谁来我给谁,或者让它等不行吗?不可以吗?可能有另外的开销?为啥对线程上锁?是不是我理解错了。
java多线程一 基本实现方法、消费者生产者队列、死锁_第2张图片
上图中,就是俩个人都在等,都不服输,就会出现死锁,代码如下:

import java.util.Date;

public class LockTest {
    public static String obj1 = "obj1";
    public static String obj2 = "obj2";
    public static void main(String[] args) {
        LockA la = new LockA();
        new Thread(la).start();
        LockB lb = new LockB();
        new Thread(lb).start();
    }
}
class LockA implements Runnable{
    public void run() {
        try {
            System.out.println(new Date().toString() + " LockA 开始执行");
            while(true){
                synchronized (LockTest.obj1) {
                    System.out.println(new Date().toString() + " LockA 锁住 obj1");
                    Thread.sleep(3000); // 此处等待是给B能锁住机会
                    synchronized (LockTest.obj2) {
                        System.out.println(new Date().toString() + " LockA 锁住 obj2");
                        Thread.sleep(60 * 1000); // 为测试,占用了就不放
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
class LockB implements Runnable{
    public void run() {
        try {
            System.out.println(new Date().toString() + " LockB 开始执行");
            while(true){
                synchronized (LockTest.obj2) {
                    System.out.println(new Date().toString() + " LockB 锁住 obj2");
                    Thread.sleep(3000); // 此处等待是给A能锁住机会
                    synchronized (LockTest.obj1) {
                        System.out.println(new Date().toString() + " LockB 锁住 obj1");
                        Thread.sleep(60 * 1000); // 为测试,占用了就不放
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

输出就是A锁住了,B锁住了,然后就不动了:

Wed Jan 10 19:36:44 GMT+08:00 2018 LockA 开始执行
Wed Jan 10 19:36:44 GMT+08:00 2018 LockA 锁住 obj1
Wed Jan 10 19:36:44 GMT+08:00 2018 LockB 开始执行
Wed Jan 10 19:36:44 GMT+08:00 2018 LockB 锁住 obj2
后面就没有了

如何避免死锁呢,别一个锁着又去锁另外一个

import java.util.Date;

public class UnLock {
    public static String obj1 = "obj1";
    public static String obj2 = "obj2";
    public static void main(String[] args) {
        LockA la = new LockA(obj1,obj2);
        new Thread(la).start();
        LockB lb = new LockB(obj1,obj2);
        new Thread(lb).start();
    }
}
class LockA implements Runnable{
    private Object obj1;
    private Object obj2;
    public LockA(Object o1,Object o2){
        this.obj1 = o1;
        this.obj2 = o2;
    }
    public void run() {
        String name = Thread.currentThread().getName();
        System.out.println(name + " acquiring lock on " + obj1);
        synchronized (obj1) {
            System.out.println(name + " acquired lock on " + obj1);
//            work();
        }
        System.out.println(name + " released lock on " + obj1);
        System.out.println(name + " acquiring lock on " + obj2);
        synchronized (obj2) {
            System.out.println(name + " acquired lock on " + obj2);
//            work();
        }
        System.out.println(name + " released lock on " + obj2);

        System.out.println(name + " finished execution.");
    }
}
class LockB implements Runnable{
    private Object obj1;
    private Object obj2;
    public LockB(Object o1,Object o2){
        this.obj1 = o1;
        this.obj2 = o2;
    }
    public void run() {
        String name = Thread.currentThread().getName();
        System.out.println(name + " acquiring lock on " + obj2);
        synchronized (obj2) {
            System.out.println(name + " acquired lock on " + obj2);
//            work();
        }
        System.out.println(name + " released lock on " + obj2);
        System.out.println(name + " acquiring lock on " + obj1);
        synchronized (obj1) {
            System.out.println(name + " acquired lock on " + obj1);
        }
        System.out.println(name + " released lock on " + obj1);

        System.out.println(name + " finished execution.");
    }
}
Thread-0 acquiring lock on obj1
Thread-1 acquiring lock on obj2
Thread-0 acquired lock on obj1
Thread-1 acquired lock on obj2
Thread-0 released lock on obj1
Thread-1 released lock on obj2
Thread-0 acquiring lock on obj2
Thread-1 acquiring lock on obj1
Thread-0 acquired lock on obj2
Thread-1 acquired lock on obj1
Thread-0 released lock on obj2
Thread-1 released lock on obj1
Thread-1 finished execution.
Thread-0 finished execution.

你可能感兴趣的:(java)