Java结束项目&线程之门

Java阶段项目

超级微信服务端项目

Java阶段的终结者!完成代码(前17条):
http://pan.baidu.com/s/1qXUgLGg
接口文档(转自优才陈军老师)
http://pan.baidu.com/s/1c16iJFq
测试数据数据表:
http://pan.baidu.com/s/1o7C9WOa

进程与线程

线程是开发中应用非常频繁的技术。在企业面试中也常被临幸。

进程:

进程是具有一定独立功能的应用程序关于某个数据集合上的一次运行活动,它是一个动态的概念。进程是系统进行资源分配和调度的一个独立单位。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响。一个进程至少有一个线程。

线程:

线程是进程的一个实体,是CPU调度和分配的基本单位,线程基本上不拥有系统资源,只拥有一点在运行过程中必不可少的资源(如堆和栈),但是它可与同属一个进程的其他线程共享进程所拥有的全部资源。线程的划分尺度小于进程,使得多线程程序的并发性高。

守护线程(Daemon):

守护线程是一个特殊的线程,Daemon线程的作用是在程序的运行期间该线程在后台提供一种服务。它只有在所有的非Daemon线程运行结束时,Daemon线程也会中止运行。如JVM中的垃圾处理机制就是一个典型的Daemon。

public class Test01_DaemonThread {
    public static void main(String[] args) {
        DaemonThread daemon = new DaemonThread();
        daemon.setDaemon(true);// 设置为守护程序
        daemon.start();
        Thread t = new Thread();
        t.start();
        Scanner scanner = new Scanner(System.in);
        final String str = scanner.nextLine();// 阻塞主线程
        scanner.close();

        new Thread(){// 创建匿名内部类的对象
            @Override
            public void run() {
                while(!str.equals("q")){
                    System.out.println("工作线程运行中...");
                    try {
                        Thread.sleep(1000*1);// 线程休眠 1000ms=1s
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }

    static class DaemonThread extends Thread{// 内部类
        @Override
        public void run() {
            System.out.println("守护线程启动");
        }
    }
}

线程的生命周期:

1、new-新建状态:创建了一个线程对象后,该线程就处于新建状态,此时线程还未启动。
2、Runnable–就绪状态:线程排队等待CPU分配运行时间。
3、Running-运行(正在运行)状态:线程获取了CPU分配的时间片段,则进入Running状态,开始执行run()方法中的代码。
4、Block-阻塞(挂起)状态:线程在执行过程中会被中断,目的是让其它线程获得执行的机会。阻塞结束时,该线程将进入Runnable状态,而非直接进入Running状态。
5、Dead-死亡状态:当线程的run()方法执行结束,线程进入Dead状态,对象将被垃圾回收,不可再回到Runnable状态。

线程的阻塞与唤醒

阻塞是指暂停一个线程的执行以等待某个条件发生(如某资源就绪)
* sleep()和interrupt():使线程沉睡固定的毫秒时间,然后再进入Runnable状态,也可以使用interrupt()方法提前唤醒线程

public class Test02_SleepAndInterrupt {
    public static void main(String[] args) {
        Thread t = new Thread(){// 匿名内部类(继承自Thread)对象
            public void run() {
                while(true){
                    System.out.println("小白在睡觉....");
                    try {
                        Thread.sleep(1000*60*10);// 线程休眠10分钟
                    } catch (InterruptedException e) {// 休眠线程被interrupt唤醒时将报异常
                        System.out.println("是谁唤醒了我?!");
                    }
                }
            }
        };
        t.start();// 启动线程

        while(true){
            String str = new Scanner(System.in).nextLine();// 创建匿名Scanner对象
            System.out.println("苏醒吧,小白!");
            t.interrupt();// 唤醒休眠中的线程
        }
    }
}
  • 同步锁(synchronized):*Java用synchronized关键字为指定的方法或对象设置同步锁*。被设置同步锁的代码块称为同步代码块。
    synchronized(对象)针对内存区块申请内存锁,内存锁是针对相同对象的互斥操作。
public class Test05_Synchronized {
    static Integer money = 1000;// 公共变量
    public static void main(String[] args) {
    // 创建3个线程
        User xiaobai = new User("xiaobai");
        User jia = new User("路人甲");
        User yi = new User("路人乙");
    // 开启3个线程
        xiaobai.start();
        jia.start();
        yi.start();
    }

    static class User extends Thread{
        public User(String name){
            super(name);
        }
        @Override
        public void run() {
        // 如果不加锁,三个对象同时访问money,可能出现-200结果
            synchronized(money){// 加锁
                if(money >= 400){
                    System.out.println(Thread.currentThread().getName()+"取出了400元。");
                    money -= 400;
                    System.out.println("还剩"+money+"元。");
                }else{
                    System.out.println("余额不足");
                }
            }
        }
    }
}
  • wait()和notify():线程执行了一个对象的wait()方法就会被挂起(阻塞),只有等到其他线程执行了该对象的notify()或notifyAll()方法才能将其唤醒。wait()必须和锁一起使用,wait在释放CPU的同时,会释放其中对象锁的控制,这也是wait和sleep最大的区别。
public class Test06_WaitAndNotify {
    public static void main(String[] args) {

        Thread t = new Thread(){
            @Override
            public void run() {
                System.out.println("小白睡觉.....");
                synchronized(this){// 对象锁
                    try {
                        wait();// 阻塞线程
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    // 唤醒后,顺序执行下面的代码
                    System.out.println("是谁呼唤我?!");
                }
            }
        };
        t.start();

        Scanner scanner = new Scanner(System.in);
        System.out.println("输入任意字符串,召唤小白!");
        String str = scanner.nextLine();

        synchronized(t){
            t.notify();// 唤醒线程
        }
    }
}
  • 临界区同步:使用join()方法后,父线程会被阻塞,等待子线程执行完毕后才会被唤醒
public class Test04_Join {
    static int result = 0;
    public static void main(String[] args) {
        Thread t = new Thread(){
            @Override
            public void run() {
                for(int i=0;i<=10;i++){// 从1加到10
                    result+=i;
                }
            }
        };
        t.start();
        try {
            t.join();// 临界同步,t为子线程,main线程为父线程
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(result);// 55
    }
}
  • 线程执行I/O操作:当线程中执行I/O操作或进行远程通信时,会因为等待相关资源而进入阻塞状态。例如当执行new Scanner(System.in).nextLine()方法时,线程会被挂起直到用户向控
    制台输入数据。

生产者-消费者模型

生产者-消费者模型是一个典型的运用线程同步机制的模型。在生产者-消费者模型中通过创建两个线程来描述线程的同步机制。一个线程模拟生产者,负责提供任务;一个线程模拟消费者,负责执行任务;任务存放在一个公共的集合中。

  • 为什么使用生产者-消费者模型?
    生产者-消费者模型是一种典型的运用了线程同步机制的模型,是一种高复用松耦合的模型。在许多情况下我们在使用多线程时会遇到线程运行时间差的问题,这种异步操作我们就可以使用生产者-消费者模型来解决。

  • 如何实现生产者-消费者模型?
    1、创建一个线程负责提供执行的任务:生产者
    2、创建一个线程负责执行任务:消费者
    3、任务存放在一个公用的集合中:仓储

    • 当仓储未满时进行生产,仓满则停止生产;
    • 消费者在仓储中有产品的时候进行消费,仓空则挂起等待(阻塞状态);
    • 当消费者发现仓储没有产品可以消费的时候应该通知生产者去生产;
    • 生产者在生产出可消费的产品时应该通知消费者去消费
// 简单的模拟
public class Test07_CreatorAndCustomer {
    static List tasks = new ArrayList();
    static Scanner scanner = new Scanner(System.in);
    public static void main(String[] args) {
        // 消费者线程
        Thread t1 = new Thread(){
            @Override
            public void run() {
                boolean flag = false;
                while(true){
                    try {
                        Thread.sleep(1000*60*60);
                    } catch (InterruptedException e) {
                        String s = "";
                        for(int i=0;i<100000;i++){
                            s+="a";
                        }// 模拟延迟执行

                        while(!tasks.isEmpty()){// 模拟消费者消费
                            String str = tasks.remove(0);
                            if(str.equals("q")){// 退出方式
                                flag = true;
                                break;
                            }
                            System.out.println(str);
                        }
                    }
                    if(flag){// 结束线程
                        break;
                    }
                }
                System.out.println("消费者线程结束!");
            }
        };
        t1.start();

        // 生产者线程
        Thread t2 = new Thread(){
            @Override
            public void run() {
                while(true){
                    System.out.println("请输入字符串:");
                    String str = scanner.nextLine();
                    tasks.add(str);
                    t1.interrupt();
                }
            }
        };
        t2.setDaemon(true);// 设置为守护程序,当消费者线程结束时,生产者线程也将中止
        t2.start();
    }
}

牛刀小试

设计4个线程,2个线程每次对j增加1,2个线程对j每次减少1。

public class HomeWork {
    private static int j;
    public static void main(String[] args) {
        for(int i=0;i<2;i++){// 调用四个线程对j操作
            Thread t1 = new Thread(new Thread_Inc());
            Thread t2 = new Thread(new Thread_Dec());
            t1.start();
            t2.start();
        }
    }

    private static synchronized void inc(){ // 方法加锁,避免异步问题
        j++;
        System.out.println("j+1="+j);
    }
    private static synchronized void dec(){ // 可以实验不加锁时的情况,与加锁的进行比较
        j--;
        System.out.println("j-1="+j);
    }

    static class Thread_Inc extends Thread{// 内部类,+
        @Override
        public void run() {
            for(int i=0;i<5;i++){
                inc();
            }
        }
    }

    static class Thread_Dec extends Thread{// 内部类,-
        @Override
        public void run() {
            for(int i=0;i<5;i++){
                dec();
            }
        }
    }
}

你可能感兴趣的:(学习历程)