Java第20天~第21天/12.2~12.3

day20

一、多线程实现的第一种方式:继承Thread类

1、多线程的实现方式一:继承Thread类
* 1)自定一个类:MyThread 继承自Thread类
* 2)在MyThread类中重写Thread类中的run()
* 3)在主线程中,创建该类的实例对象,启动线程

package org.westos_02_实现多线程第一种方式_继承Thread;
/**
 * 多线程程序实现方式1:
 *      1)自定一个类:MyThread 继承自Thread类
 *      2)在MyThread类中重写Thread类中的run()
 *      3)在主线程中,创建该类的实例对象,启动线程
 * @author 小鑫
 */
public class ThreadDemo {

    public static void main(String[] args) {

        //创建该线程的实例对象
        MyThread t1 = new MyThread();
        //启动线程
        //t.run();
        //启动线程不是调用run()方法,run()方法只是一个普通的方法,并不会出现线程随机性
        //启动线程用的是start()方法,通过JVM调用线程中的run()来进行多个线程抢占cpu执行权
        t1.start();
        //t.start();//java.lang.IllegalThreadStateException
        //同一个对象线程只能启动一次,第二次报异常:非法线程状态异常
        MyThread t2 = new MyThread();
        t2.start();
    }
}

class MyThread extends Thread{

    @Override
    public void run() {
        for (int x = 0; x < 100; x++) {
            System.out.println("hello" + x);
        }
    }

}

这里写图片描述
2、获取多线程名称

package org.westos_03_获取多线程名称;
/**
 * public final String getName()返回该线程的名称。
 * public final void setName(String name)改变线程名称,使之与参数 name 相同。 
 * public static Thread currentThread():表示正在运行的线程
 * @author 小鑫
 *
 */
public class ThreadDemo {

    public static void main(String[] args) {

        //无参构造形式
        //wuCan();
        //有参构造
        youCan();

    }

    private static void youCan() {
        //有参构造方式
        //创建线程类实例
        MyThread my1 = new MyThread("王五");
        MyThread my2 = new MyThread("赵六");
        //启动线程
        my1.start();
        my2.start();

    }

    private static void wuCan() {
        //创建线程类的实例
        //无参构造方式
        MyThread my1 = new MyThread();
        MyThread my2 = new MyThread();
        //设置名称
        //public final void setName(String name)
        my1.setName("张三");
        my1.setName("李四");

        //public static Thread currentThread():表示正在运行的线程
        //默认所有的子线程的都在主线程中
        System.out.println(Thread.currentThread().getName());//main
        //分别启动线程
        my1.start();
        my2.start();
    }
}

class MyThread extends Thread{

    //无参构造
    public MyThread(){

    }
    //有参构造
    public MyThread(String name){
        super(name);
    }
    @Override
    ////my1和my2子线程都会执行这段代码,两个子线程在互相抢占CPU的执行权
    public void run() {
        for(int x=0;x<100;x++){
            System.out.println("hello"+x);
        }
    }


}

3、线程终止
public final void join() throws InterruptedException等待该线程终止。

package org.westos_04_线程终止_线程暂停_线程优先级;
/**
 * public final void join()
       throws InterruptedException等待该线程终止。 
 * 其他线程要等待该线程终止后才能开始运行
 * @author 小鑫
 */
public class JoinDemo {

    public static void main(String[] args) {
        //无参构造
        //创建线程实例对象
        MyJoin mj1 = new MyJoin();
        MyJoin mj2 = new MyJoin();
        MyJoin mj3 = new MyJoin();
        //设置名称
        mj1.setName("张三");
        mj2.setName("李四");
        mj3.setName("王五");
        //启动线程
        mj1.start();
        try {
            mj1.join();
        } catch (InterruptedException e) {
            // 中断异常
            e.printStackTrace();
        }
        mj2.start();
        mj3.start();


    }
}

class MyJoin extends Thread{

    @Override
    public void run() {
        for(int x=0;x<100;x++){
            System.out.println(getName()+":"+x);
        }
    }


}

4、线程的暂停
public static void yield()暂停当前正在执行的线程对象,并执行其他线程。

package org.westos_04_线程终止_线程暂停_线程优先级;
/**
 * public static void yield()暂停当前正在执行的线程对象,并执行其他线程。
 * 暂停当前线程执行其他线程,并不保证另一个线程就一定能抢占到CPU的执行权
 * 暂停之后,二者重新抢夺CPU执行权
 * @author 小鑫
 *
 */
public class YieldThreadDemo {

    public static void main(String[] args) {
        //创建线程实例对象
        //无参构造
        MyYieldThread my1 = new MyYieldThread();
        MyYieldThread my2 = new MyYieldThread();
        //设置名称
        my1.setName("张三");
        my2.setName("李四");
        //启动线程
        my1.start();
        my2.start();
    }
}

class MyYieldThread extends Thread{

    @Override
    public void run() {
        for(int x=0;x<100;x++){
            System.out.println(getName()+":"+x);
            //public static void yield():暂停当前线程
            Thread.yield();
        }
    }


}

5、线程的优先级
public final int getPriority()返回线程的优先级。

package org.westos_04_线程终止_线程暂停_线程优先级;
/**
 * public final int getPriority()返回线程的优先级。 
 * 默认优先级是5
 *  java.lang.Thread 
        public static final int MAX_PRIORITY 10  :最大优先级 
        优先级大的抢占到CPU的执行权大,并不代表就一定能抢到,因为线程的执行具有随机性!
        public static final int MIN_PRIORITY 1   :最小优先级
        public static final int NORM_PRIORITY 5  :默认优先级
 * @author 小鑫
 *
 */
public class PriorityDemo {

    public static void main(String[] args) {
        //有参构造
        //创建线程实例对象
        MyPaiority mp1 = new MyPaiority("刘备");
        MyPaiority mp2 = new MyPaiority("关羽");
        MyPaiority mp3 = new MyPaiority("张飞");
        //获取优先级
        //System.out.println(mp1.getPriority());//5
        //System.out.println(mp2.getPriority());//5
        //System.out.println(mp3.getPriority());//5

        //设置优先级
        mp1.setPriority(10);
        mp3.setPriority(1);
        //启动线程
        mp1.start();
        mp2.start();
        mp3.start();
    }
}

class MyPaiority extends Thread{

    public MyPaiority() {
        super();
    }

    public MyPaiority(String name) {
        super(name);
    }

    @Override
    public void run() {
        for(int x=0;x<100;x++){
            System.out.println(getName()+":"+x);
        }
    }


}

6、线程睡眠

package org.westos_05_线程睡眠_线程停止_守护线程;

import java.util.Date;

public class SleepDemo {

    public static void main(String[] args) {
        //创建线程实例对象
        ThreadSleep ts1 = new ThreadSleep();
        ThreadSleep ts2 = new ThreadSleep();
        ThreadSleep ts3 = new ThreadSleep();
        //设置名称
        ts1.setName("线程1");
        ts2.setName("线程2");
        ts3.setName("线程3");
        //启动线程
        ts1.start();
        ts2.start();
        ts3.start();
    }
}

class ThreadSleep extends Thread{

    @Override
    public void run() {
        for(int x=1;x<=30;x++){
            System.out.println(getName()+":"+x+",日期:"+new Date());
            //睡眠1秒
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }


}

7、停止线程和中断线程
public final void stop():强迫线程停止执行
public void interrupt()中断线程。 表示中断线程一种状态

package org.westos_05_线程睡眠_线程停止_守护线程;

import java.util.Date;
/**
 * public final void stop():强迫线程停止执行
 * public void interrupt()中断线程。 表示中断线程一种状态
 * @author 小鑫
 *
 */
public class StopDemo {

    public static void main(String[] args) {
        //创建线程实例对象
        StopThread st = new StopThread();
        //启动线程
        st.start();
        //开始执行Tue Dec 05 20:12:10 CST 2017
        //结束执行Tue Dec 05 20:12:15 CST 2017

        //三秒睡不醒,停止它
        try {
            Thread.sleep(3000);
            //st.stop();//中间那条线表示过时了
            //开始执行Tue Dec 05 20:11:40 CST 2017
            st.interrupt();
            //开始执行Tue Dec 05 20:12:55 CST 2017
            //线程睡着了
            //结束执行Tue Dec 05 20:12:58 CST 2017
            //能打印线程睡着了,说明走catch语句,即中断try语句
        } catch (InterruptedException e) {
            e.printStackTrace();
        }       
    }
}

class StopThread extends Thread{

    @Override
    public void run() {
        System.out.println("开始执行"+new Date());
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            System.out.println("线程睡着了");
        }
        System.out.println("结束执行"+new Date());
    }


}

8、守护线程
public final void setDaemon(boolean on) on指定true,就是设置守护线程…
将该线程标记为守护线程或用户线程。

package org.westos_05_线程睡眠_线程停止_守护线程;
/**
 * public final void setDaemon(boolean on)  on指定true,就是设置守护线程...
 * 将该线程标记为守护线程或用户线程。
 * 当正在运行的线程都是守护线程时,Java 虚拟机退出。 
 * 该方法必须在启动线程前调用。
 * jvm自动退出,对于主线程的数据如果直接输出完毕,对于两个守护线程来说不会立即消失,Jvm等会就自动退出.
 * @author 小鑫
 *
 */
public class DemaonDemo {

    public static void main(String[] args) {
        //创建线程实例对象
        MyDemaonThread mt1 = new MyDemaonThread();
        MyDemaonThread mt2 = new MyDemaonThread();
        //设置名称
        mt1.setName("守护1");
        mt2.setName("守护2");
        //设置守护线程
        mt1.setDaemon(true);
        mt2.setDaemon(true);
        //启动线程
        mt1.start();
        mt2.start();
        //设置被守护线程
        Thread.currentThread().setName("被守护线程");
        for(int x=0;x<5;x++){
            System.out.println(Thread.currentThread().getName()+":"+x);
        }
    }
}

class MyDemaonThread extends Thread{

    @Override
    public void run() {
        for(int x=0;x<100;x++){
            System.out.println(getName()+":"+x);
        }
    }


}

二、多线程实现的第二种方式:Runnable接口

1、多线程实现的第二种方式:Runnable接口
* 1)自定义一个类MyRunnable,该类实现Runnable接口
* 2)实现该接口中的run()方法
* 3)在主线程中创建该类的实例对象,
* 4)创建Thread类对象,将3)创建的这个对象作为参数进行传递
* 5)分别启动线程

package org.westos_06_实现多线程第二种方式_Runnable接口;
/**
 * 多线程实现的第二种方式:(实际开发中第二种比第一种应用更广泛)
 *      开发步骤:
 *  1)自定义一个类MyRunnable,该类实现Runnable接口
 *  2)实现该接口中的run()方法
 *  3)在主线程中创建该类的实例对象,
 *  4)创建Thread类对象,将3)创建的这个对象作为参数进行传递
 *  5)分别启动线程
 * @author 小鑫
 *
 */
public class ThreadDemo {

    public static void main(String[] args) {
        //创建MyRunnable实例对象
        MyRunnable my= new MyRunnable();
        //创建线程对象
        //public Thread(Runnable target)
        //Thread t1 = new Thread(my);
        //Thread t2 = new Thread(my);
        //public Thread(Runnable target,String name)
        Thread t1 = new Thread(my, "线程1");
        Thread t2 = new Thread(my, "线程2");
        t1.start();
        t2.start();
    }
}
class MyRunnable implements Runnable{

    @Override
    public void run() {
        for(int x=0;x<100;x++){
            //getName()是Thread类中的方法,间接使用Thread类的静态功能获得线程名称
            System.out.println(Thread.currentThread().getName()+":"+x);
        }

    }

}

2、检验多线程安全问题的标准(以后在判断一个多线程序是否有安全问题的标准)
* 1)当前是否是一个多线程环境
* 2)多线程环境中是否有共享数据
* 3)是否有多条语句对共享数据进行操作

package org.westos_07_模拟多线程_电影院卖票案例;
/**
 * 为了模拟电影院卖票更真实的场景,每一个窗口卖票应该延迟操作
 *  在接口自实现类中,在run()方法中让每一个线程执行睡眠0.1秒
 * 
 *加入延迟操作:
 *      1)一张票可能被卖多次
 *              100张票会出现多次
 *          CPU的执行具有原子性操作
 *      2)可能出现负票
 *          1,0,-1
 *      延迟操作和线程随机性导致
 *
 *
 *这两种情况都属于线程安全问题,现在写的这个代码是一种有问题的代码?
 *  如何解决多线程的安全问题呢?
 *  检验多线程安全问题的标准(以后在判断一个多线程序是否有安全问题的标准)
 *      1)当前是否是一个多线程环境
 *      2)多线程环境中是否有共享数据
 *      3)是否有多条语句对共享数据进行操作
 *
 *就目前这个电影院卖票这个案例,
 *      1)是多线程环境,因为要实现3个窗口同时卖票
 *      2)有共享数据,比如:tickets
 *      3)有多条语句对当前这个共享数据进行操作
 *      
 *优化改进:
 *  1)多线程环境和共享数据改变不了,突破口就是3)条件:将多条语句对共享数据的操作进行更改
 *  
 *      将多条语句对共享数据进行操作的代码用代码块包起来
 *      使用同步代码块:synchronized(同步锁对象){
 *              多条语句对共享数据的操作;
 *      }
 * @author 小鑫
 */
public class SellTicketDemo {

    public static void main(String[] args) {
        //创建线程实例对象
        TicketThread tt1 = new TicketThread();
        TicketThread tt2 = new TicketThread();
        TicketThread tt3 = new TicketThread();
        //设置名称
        tt1.setName("窗口1");
        tt2.setName("窗口2");
        tt3.setName("窗口3");
        //启动线程
        tt1.start();
        tt2.start();
        tt3.start();
    }
}
class TicketThread extends Thread{

    //private int tickets=100;
    //定义100张票,票被三个线程公用,用static修饰
    private static int tickets=100;
    @Override
    public void run() {
        while(true){
            try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            if(tickets>0){              
                System.out.println(getName()+"正在出售第"+(tickets--)+"张票");
            }
        }
    }


}

3、多线程同步机制

package org.westos_08_线程同步机制_电影院卖票案例;

/**
 * 就目前这个电影院卖票这个案例, 1)是多线程环境,因为要实现3个窗口同时卖票 2)有共享数据,比如:tickets
 * 3)有多条语句对当前这个共享数据进行操作
 * 
 * 优化改进: 1)多线程环境和共享数据改变不了,突破口就是3)条件:将多条语句对共享数据的操作进行更改
 * 
 * 将多条语句对共享数据进行操作的代码用代码块包起来 Java的同步机制: 使用同步代码块:synchronized(同步锁对象){
 * 多条语句对共享数据的操作; }
 * 
 * 同步锁对象:应该每一个线程都要使用这个锁对象(同步锁):理解为门的开和关 使用同步代码块可以解决线程安全问题
 * 
 * @author 小鑫
 * 
 */
public class SellTicketDemo {

    public static void main(String[] args) {
        // 创建TicketThread对象
        TicketThread tt = new TicketThread();
        // 创建线程对象
        Thread t1 = new Thread(tt, "窗口1");
        Thread t2 = new Thread(tt, "窗口2");
        Thread t3 = new Thread(tt, "窗口3");
        // 启动线程
        t1.start();
        t2.start();
        t3.start();
    }
}

class TicketThread implements Runnable {

    // 定义100张票
    private static int tickets = 100;
    // 设置锁对象,三个线程必须使用同一个锁对象
    // 可以是Object类型,任意的Java类
    private Object obj = new Object();

    @Override
    public void run() {
        // 一直邮有票
        while (true) {
            // 睡眠0.1秒
            synchronized (obj) {
                if (tickets > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()
                            + "正在出售第" + (tickets--) + "张票");
                }
            }
        }

    }

}

4、同步方法

package org.westos_09_线程同步机制_同步方法_电影院卖票案例;

/**
 * 同步方法
 * @author 小鑫
 */
public class SellTeckesDemo {

    public static void main(String[] args) {

        // 创建TecketThread对象
        TecketThread tt = new TecketThread();
        // 创建线程实例对象
        Thread t1 = new Thread(tt, "窗口1");
        Thread t2 = new Thread(tt, "窗口2");
        Thread t3 = new Thread(tt, "窗口3");
        // 启动线程
        t1.start();
        t2.start();
        t3.start();
    }
}

class TecketThread implements Runnable {

    // 定义100张被共用的票,不能修改
    private static int tickets = 100;
    // 创建锁对象
    private Object obj = new Object();

    private int x;

    @Override
    public void run() {
        while (true) {
            if (x % 2 == 0) {
                //静态时的同步锁对象--->类名.class
                //静态同步方法:要通过反射获取Class类对象(当前类的字节码文件对象)
                synchronized (TecketThread.class) {
                    if (tickets > 0) {
                        try {
                            //睡眠0.1秒
                            Thread.sleep(100);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName()
                                + "正在出售第" + (tickets--) + "张票");
                    }
                }
            } else {
                //sellTicket();
            }

        }

    }

    // 非静态同步方法,锁对象是this
    /*private synchronized void sellTicket() {
        if (tickets > 0) {
            // 设置线程睡眠0.1秒
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "正在出售第"
                    + (tickets--) + "张票");
        }

    }*/

    //静态同步方法,锁对象是(类名.class)
    private static synchronized void sellTicket() {
        if (tickets > 0) {
            // 设置线程睡眠0.1秒
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + "正在出售第"
                    + (tickets--) + "张票");
        }

    }

}

day21

一、同步锁

1、Lock锁
* Jdk5以后Java提供了一个更具体的锁对象:Lock Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作
* Lock是一个接口,所以它在使用的是 ReentrantLock子实现类
* public void lock()获取锁。

package org.westos_01_Lock锁;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * public void lock()获取锁。 
 * public void unlock()试图释放此锁
 * 
 * @author 小鑫
 */
public class SellTicketDemo {

    public static void main(String[] args) {

        // 创建TicketThread对象
        TicketThread tt = new TicketThread();
        // 创建线程实例对象
        Thread t1 = new Thread(tt, "窗口1");
        Thread t2 = new Thread(tt, "窗口2");
        Thread t3 = new Thread(tt, "窗口3");
        // 启动线程
        t1.start();
        t2.start();
        t3.start();
    }
}

class TicketThread implements Runnable {

    // 定义100张票
    private static int tickets = 100;
    // 锁对象
    private Object obj = new Object();
    // 定义一个具体锁对象
    private Lock l = new ReentrantLock();

    @Override
    public void run() {

        // oldMethod();

        // 一直有票
        while (true) {
            // 获取锁
            try {
                l.lock();
                if (tickets > 0) {
                    // 睡眠0.1秒
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "正在出售第"
                            + (tickets--) + "张票");
                }
            } finally{
                //释放锁对象
                l.unlock();
            }
        }

    }

    private void oldMethod() {
        // 一直有票
        while (true) {
            synchronized (obj) {
                if (tickets > 0) {
                    // 睡眠0.1秒
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()
                            + "正在出售第" + (tickets--) + "张票");
                }
            }
        }
    }

}

2、死锁现象
* 死锁线程:两个或者两个以上的线程出现了互相等待的情况,就会出现死锁!

package org.westos_02_死锁;
/**
 * 使用同步机制可以解决多线程的安全问题,但是自身也会有弊端:
 *  1)同步---->执行效率低(每一个线程在抢占到CPU的执行权,会去将(门)关闭,别的线程进不来)
 *  2)容易出现死锁现象
 * @author 小鑫
 */
public class DieLockDemo {

    public static void main(String[] args) {

        //创建线程对象
        DieLock dl1 = new DieLock(true);
        DieLock dl2 = new DieLock(false);
        //启动线程
        dl1.start();
        dl2.start();
    }
}

class MyLock{
    //创建两把锁对象
    public static final Object objA = new Object();
    public static final Object objB = new Object();
}

class DieLock extends Thread{

    //定义一个成员变量
    private boolean flag;

    public DieLock(boolean flag){
        this.flag=flag;
    }
    @Override
    public void run() {
        if(flag){
            synchronized(MyLock.objA){
                System.out.println("if objA");
                synchronized (MyLock.objB) {
                    System.out.println("if objB");
                }
            }
        }else{
            synchronized(MyLock.objB){
                System.out.println("else objB");
                synchronized(MyLock.objA){
                    System.out.println("else objA");
                }
            }
        }
    }


}

3、生产者消费者模式

package org.westos_03_生产者消费者模式;
/**
 * 
 * @author 小鑫
 */
public class StudentDemo {

    public static void main(String[] args) {

        //创建一个资源对象
        Student s=new Student();
        //创建生产者消费者资源对象
        SetThread st = new SetThread(s);
        GetThread gt = new GetThread(s);
        //创建线程对象
        Thread t1 = new Thread(st);
        Thread t2 = new Thread(gt);
        //启动线程
        t1.start();
        t2.start();
    }
}

//资源对象类
class Student{
    String name;
    int age;
}

//生产者类
class SetThread implements Runnable{

    private Student s;
    public SetThread(Student s){
        this.s=s;
    }
    @Override
    public void run() {
        //设置资源数据
        s.name="张三";
        s.age=30;
    }

}

//消费者类
class GetThread implements Runnable{

    private Student s;
    public GetThread(Student s){
        this.s=s;
    }
    @Override
    public void run() {
        System.out.println(s.name+"---"+s.age);
    }

}

4、同步机制生产者消费者模式

package org.westos_04_同步生产者消费者模式;

/**
 * 
 * @author 小鑫
 */
public class StudentDemo {

    public static void main(String[] args) {

        //创建资源对象
        Student s = new Student();
        //创建生产者消费者资源对象
        SetThread st = new SetThread(s);
        GetThread gt = new GetThread(s);
        //创建线程对象
        Thread t1 = new Thread(st);
        Thread t2 = new Thread(gt);
        //启动线程
        t1.start();
        t2.start();
    }
}

// 学生资源对象类
class Student {

    String name;
    int age;
}

// 生产者线程
class SetThread implements Runnable {

    private Student s;

    public SetThread(Student s) {
        this.s = s;
    }

    private int x;

    @Override
    public void run() {
        // 同步机制
        while (true) {
            synchronized (s) {
                if (x % 2 == 0) {
                    s.name = "张三";
                    s.age = 30;
                } else {
                    s.name = "李四";
                    s.age = 40;
                }
                x++;
            }
        }
    }
}

//消费者线程
class GetThread implements Runnable{

    private Student s;
    public GetThread(Student s){
        this.s=s;
    }
    @Override
    public void run() {

        while(true){
            synchronized (s) {
                System.out.println(s.name + "---" + s.age);
            }
        }
    }

}

5、同步机制等待唤醒机制生产者消费者模式

package org.westos_05_同步机制_等待唤醒机制_生产者消费者模式;
/**
 * 
 * @author 小鑫
 */
public class StudentDemo {

    public static void main(String[] args) {

        //创建资源对象
        Student s = new Student();
        //创建生产者消费者资源对象
        SetThread st = new SetThread(s);
        GetThread gt = new GetThread(s);
        //创建线程对象
        Thread t1 = new Thread(st);
        Thread t2 = new Thread(gt);
        //启动线程
        t1.start();
        t2.start();

    }
}

//资源对象学生类
class Student{

    String name;
    int age;
    //声明标记
    boolean flag;//默认没有数据,如果true,则说明有数据
}

//生产者线程
class SetThread implements Runnable{

    private Student s;
    public SetThread(Student s){
        this.s=s;
    }
    private int x;
    @Override
    public void run() {
        while(true){
            //同步机制
            synchronized(s){
                //判断是否有数据
                /**
                 * 如果生产者先抢到CPU执行权,判断是否有数据
                 * 如果没有数据,则释放锁对象,生产数据;
                 * 如果有数据了,修改标记,通知消费者消费数据,唤醒等待状态
                 */
                if(s.flag){
                    //等待
                    try {
                        s.wait();//阻塞式方法,立即释放锁
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                if(x%2==0){
                    s.name="张三";
                    s.age=30;
                }else{
                    s.name="李四";
                    s.age=40;
                }
                x++;

                //修改标记
                s.flag=true;
                //有数据了,通知t2消费者线程来消费数据
                //唤醒等待这种状态
                s.notify();
            }
        }
    }   
}

//消费者线程
class GetThread implements Runnable{

    private Student s;
    public GetThread(Student s){
        this.s=s;
    }
    @Override
    public void run() {
        while(true){
            synchronized(s){
                //判断是否有数据               
                /**
                 * 消费者先抢到CPU执行权,判断是否有数据,如果有数据则输出;
                 * 如果没有数据,立即释放锁对象,并修改标记,通知生产者生产数据,唤醒等待状态
                 */
                if(!s.flag){
                    try {
                        s.wait();//调用时立即释放锁
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println(s.name+"---"+s.age);

                //修改标记
                s.flag=false;
                //通知t1生产者线程,没有数据了,该生产数据了
                //唤醒t1线程
                s.notify();

            }
        }
    }

}

6、最终版生产者消费者模式

package org.westos_06_最终版_生产者消费者模式;
/**
 * 最终版代码:
 *      现在将资源对象Student中的成员变量私有化
 *      并且给当前类中提供两个方法,同步方法
 *      在两个线程:生产者线程和消费者中线程,注意调用这两个方法就可以了!
 * @author 小鑫
 *
 */
public class StudentDemo {

    public static void main(String[] args) {

        //创建资源对象
        Student s = new Student();
        //创建生产消费资源对象
        SetThread st = new SetThread(s);
        GetThread gt = new GetThread(s);
        //创建线程对象
        Thread t1 = new Thread(st);
        Thread t2 = new Thread(gt);
        //启动线程
        t1.start();
        t2.start();
    }
}

class Student{

    private String name;
    private int age;
    //声明一个变量
    private boolean flag;
    //默认没有数据

    //set(String name,int age)方法,产生数据数据
    public synchronized void set(String name, int age){
        //判断是否有数据
        if(this.flag){
            //没有数据,等待状态
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //产生数据
        this.name=name;
        this.age=age;
        //修改标记
        this.flag=true;
        //有数据了,通知消费者线程
        this.notify();//唤醒等待这种状态

    }

    public  synchronized void get(){
        if(!this.flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(this.name+"---"+this.age);

        //修改标记
        this.flag=false;
        //通知生产者线程,没有数据,该生产数据
        this.notify();//唤醒生产者线程
    }

}

//生产者线程
class SetThread implements Runnable{

    private Student s;
    public SetThread(Student s){
        this.s=s;
    }
    private int x;
    @Override
    public void run() {
        while(true){
            if(x%2==0){
                s.set("张三", 30);
            }else{
                s.set("李四", 40);
            }
            x++;
        }
    }

}

//消费者线程
class GetThread implements Runnable{

    private Student s;
    public GetThread(Student s){
        this.s=s;
    }
    @Override
    public void run() {
        while(true){
            s.get();
        }

    }

}

二、线程组

  • 线程组表示一个线程的集合:Java允许一个线程中有多个线程
package org.westos_07_线程组;

/**
 * 线程组表示一个线程的集合:Java允许一个线程中有多个线程
 * @author 小鑫
 */
public class ThreadGroupDemo {

    public static void main(String[] args) {

        //获取线程组名称
        //method1();

        //设置线程组名称
        method2();

    }

    //设置线程组名称
    private static void method2() {
        //public ThreadGroup(String name)构造一个新线程组
        ThreadGroup tg = new ThreadGroup("新线程");

        //创建资源对象
        MyRunnable my = new MyRunnable();

        //public Thread(ThreadGroup group,Runnable target ,String name){}
        //创建线程类对象,并且将线程组对象作为参数进行传递
        Thread t1 = new Thread(tg, my, "线程1");
        Thread t2 = new Thread(tg, my, "线程2");

        ThreadGroup tg1 = t1.getThreadGroup();
        ThreadGroup tg2 = t2.getThreadGroup();

        System.out.println(tg1.getName());
        System.out.println(tg2.getName());

    }

    //获取线程组名称
    private static void method1() {
        //创建资源对象
        MyRunnable my = new MyRunnable();
        //创建线程对象
        Thread t1 = new Thread(my);
        Thread t2 = new Thread(my);
        //启动线程
        //t1.start();
        //t2.start();
        //获取线程组对象
        //public final ThreadGroup getThreadGroup()返回该线程所属的线程组
        ThreadGroup tg1 = t1.getThreadGroup();
        ThreadGroup tg2 = t2.getThreadGroup();
        //获取线程组名称
        String name1 = tg1.getName();
        String name2 = tg2.getName();

        //子线程默认线程组名称:main
        System.out.println(name1);//main
        System.out.println(name2);//main
        //所以线程默认线程组名称是main
        System.out.println(Thread.currentThread().getThreadGroup().getName());
    }
}

class MyRunnable implements Runnable {

    @Override
    public void run() {
        for (int x = 0; x < 100; x++) {
            System.out.println(Thread.currentThread().getName() + ":" + x);
        }

    }

}

三、多线程实现的第三种方式

1、Executors工厂类产生线程池

package org.westos_08_线程池;

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

/**
 * 多线程程序的实现方式3:
 * Executors工厂类来产生线程池 public static ExecutorService
newFixedThreadPool(int nThreads) Executors工厂类中的这个方法参数直接指定在当前线程池中有多少个线程
 * 方法的返回值是ExecutorService对象,该对象表示一个线程池 ExecutorsService :
 * 接口中的方法 Future<?>submit(Runnable task) <T> Future<T> submit(Callable<T> task)
 * @author 小鑫
 */
public class ExecutorsDemo {

    public static void main(String[] args) {

        //创建线程对象,使用Executors工厂类
        //public static ExecutorService newFixedThreadPool(int nThreads)
        ExecutorService pool = Executors.newFixedThreadPool(2);

        //使用ExecutorsService(跟着多个异步任务)方法
        //submit(Runnable task)
        pool.submit(new MyRunnable());
        pool.submit(new MyRunnable());
        //结束线程池
        pool.shutdown();
        //pool-1-thread-1:x
        //pool-1-thread-2:x
    }
}

class MyRunnable implements Runnable {

    @Override
    public void run() {
        for (int x = 0; x < 100; x++) {
            System.out.println(Thread.currentThread().getName() + ":" + x);
        }

    }

}

2、Callable接口

package org.westos_08_线程池;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * ExecutorsService :接口中的方法
 * <T> Future<T> submit(Callable<T> task)
 * 该返回值表示:异步计算的结果!
 * @author 小鑫
 */
public class CallableDemo {

    public static void main(String[] args) {

        //创建线程对象,工厂类
        ExecutorService Threadpool = Executors.newFixedThreadPool(2);
        //提交Callable任务(异步任务)
        Threadpool.submit(new MyCallable());
        Threadpool.submit(new MyCallable());
        //结束线程
        Threadpool.shutdown();
        //pool-1-thread-1:x
        //pool-1-thread-2:x
    }
}

class MyCallable implements Callable<Object>{

    @Override
    public Object call() throws Exception {
        for(int x=0;x<100;x++){
            System.out.println(Thread.currentThread().getName()+":"+x);
        }
        return null;
    }

}

3、Callable接口求和

package org.westos_09_线程池Callable求和;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

public class CallableDemo2 {

    public static void main(String[] args) throws InterruptedException, ExecutionException {

        //创建线程对象,工厂类
        ExecutorService Threadpool = Executors.newFixedThreadPool(2);
        //提交两个异步任务,计算1-100,1-200的和
        Future<Integer> f1 = Threadpool.submit(new MyCallable(100));
        Future<Integer> f2 = Threadpool.submit(new MyCallable(200));
        //分别调用Future接口中  get()方法,返回具体的结果
        Integer i1 = f1.get();
        Integer i2 = f2.get();
        System.out.println("1-100的和是:"+i1);
        System.out.println("1-200的和是:"+i2);
        //1-100的和是:5050
        //1-200的和是:20100

    }
}

class MyCallable implements Callable<Integer>{

    private int number;
    public MyCallable(int number){
        this.number=number;
    }

    @Override
    public Integer call() throws Exception {
        int sum=0;
        for(int x=1;x<=number;x++){
            sum += x;
        }
        return sum;     
    }

}

4、多线程匿名内部类
多线程中匿名内部类的方式
* new 类名(具体类,抽象类),接口{
* 重写/实现方法;
* }
匿名内部类本质:
* 继承该类或者实现该接口的子类对象

package org.westos_09_线程池Callable求和;
/**
 * 多线程中匿名内部类的方式
 *    new 类名(具体类,抽象类),接口{
 *        重写/实现方法;
 *    }
 * 匿名内部类本质:
 *       继承该类或者实现该接口的子类对象
 * @author 小鑫
 */
public class ThreadDemo {

    public static void main(String[] args) {

        //继承Thread类
        new Thread(){
            @Override
            public void run(){
                for(int x=0;x<100;x++){
                    System.out.println(getName()+":"+x);
                }
            }
        }.start();

        //Runnable接口
        new Thread(new Runnable(){
            @Override
            public void run(){
                for(int x = 0 ; x < 100 ; x ++){
                    System.out.println(Thread.currentThread().getName()+":"+x);
                }
            }
        }).start();

        new Thread(new Runnable(){

            @Override
            public void run() {
                for(int x = 0 ; x <100 ; x ++){
                    System.out.println("hello"+x);
                }       
            }       
        }){
            @Override
            public void run() {
                for(int x = 0 ; x <100 ; x ++){
                    System.out.println("world"+x);
                }
            }
        }.start();
    }
}

四、定时器Timer

定时器:Timer
* public void schedule(TimerTask task,Date time)安排在指定的时间执行指定的任务
* public void schedule(TimerTask task, long delay)在多少毫秒后执行指定任务
* public void schedule(TimerTask task, long delay, long period)在多少毫秒后,执行任务,并且每个多少毫秒重复执行
* public void cancel()终止此计时器,丢弃所有当前已安排的任务

1、 public void schedule(TimerTask task, long delay)在多少毫秒后执行指定任务

package org.westos_10_定时器Timer;

import java.util.Timer;
import java.util.TimerTask;

/**
 * 需求:3秒后执行爆炸任务
 * @author 小鑫
 */
public class TimerDemo {

    public static void main(String[] args) {

        //创建计时器
        Timer t = new Timer();
        //public void schedule(TimerTask task, long delay)在多少毫秒后执行指定任务
        t.schedule(new MyTask(t), 3000);
    }
}
class MyTask extends TimerTask{

    private Timer t;

    public MyTask(){

    }

    public MyTask(Timer t){
        this.t=t;
    }
    @Override
    public void run() {
        System.out.println("boom...");
        t.cancel();//取消任务
    }

}

2、安排在指定的时间执行指定的任务

package org.westos_10_定时器Timer;

import java.util.Timer;
import java.util.TimerTask;

/**
 * public void schedule(TimerTask task, long delay, long period)
 * 在多少毫秒后,执行任务,并且每个多少毫秒重复执行
 * 
 * 需求:3秒后执行爆炸任务,每隔2秒重复爆炸
 * @author 小鑫
 */
public class TimerDemo2 {

    public static void main(String[] args) {
        //创建计时器
        Timer t = new Timer();

        t.schedule(new MyTask2(), 3000, 2000);
    }
}

class MyTask2 extends TimerTask{

    @Override
    public void run() {
        System.out.println("boom...");

    }

}

3、在指定的时间删除我们的指定目录

package org.westos_10_定时器Timer;

import java.io.File;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

/**
 * 需求:在指定的时间删除我们的指定目录
 * @author 小鑫
 */
public class TimerTest {

    public static void main(String[] args) throws ParseException {
        //创建定时器
        Timer t = new Timer();
        //指定删除日期
        String s="2017-12-8 10:40:00";
        //创建SimpleDateFormat对象
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = sdf.parse(s);
        //public void schedule(TimerTask task,Date time)安排在指定的时间执行指定的任务
        t.schedule(new DeleteFolder(), date);
    }
}

class DeleteFolder extends TimerTask{

    @Override
    public void run() {
        File srcFolder = new File("demo");
        deleteFolder(srcFolder);

    }

    private void deleteFolder(File srcFolder) {

        //获取srcFolder文件及文件夹数组
        File[] fileArray = srcFolder.listFiles();
        //非空判断
        if(fileArray!=null){
            for(File file:fileArray){
                //判断是否是文件夹
                if(file.isDirectory()){
                    //递归删除,回到该方法
                    deleteFolder(file);
                }else{
                    //不是文件夹,直接删除
                    System.out.println(file.getName()+"---"+file.delete());
                }
            }
            System.out.println(srcFolder.getName()+"---"+srcFolder.delete());
        }
    }

}

五、IO流存入文件注册登录案例

用户实体类

package org.westos_11_User;
/**
 * 用户实体
 * @author 小鑫
 *
 */
public class User {

    private String username;
    private String password;

    public User(){

    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }


}

注册登录接口

package org.westos_11_User;

public interface UserDao {

    /**
     * 用户登录功能
     * 
     * @param username
     *        登录输入的用户名
     * @param password
     *        登录输入的密码
     * @return 
     *        返回是否登录成功
     */
    public abstract boolean isLogin(String username, String password);

    /**
     * 用户注册功能
     * @param user
     */
    public abstract void regist(User user);
}

用户操作接口实现类

package org.westos_11_User;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

/**
 * 用户操作接口实现类
 * @author 小鑫
 *
 */
public class UserDaoImpl implements UserDao {

    //File对象封装文件
    private static  File file=new File("user.txt");
    static{
        try {
            file.createNewFile();
        } catch (IOException e) {
            System.out.println("文件创建失败");
        }
    }

    //登录功能
    @Override
    public boolean isLogin(String username, String password) {
        //定义标记
        boolean flag=false;
        //创建字符输入流
        BufferedReader br=null;
        try {
            br=new BufferedReader(new FileReader(file));
            //一次读一行
            String line=null;
            while((line=br.readLine())!=null){
                String[] s = line.split("=");
                if(s[0].equals(username) && s[1].equals(password)){
                    //登录成功,修改标记
                    flag=true;
                }
            }
        } catch (FileNotFoundException e) {
            System.out.println("登录时找不到文件导致失败");
        } catch (IOException e) {
            System.out.println("用户登录失败");
        }finally{
            //释放资源
            if(br!=null){
                try {
                    br.close();
                } catch (IOException e) {
                    System.out.println("释放资源失败");
                }
            }
        }
        return flag;
    }

    //注册功能
    @Override
    public void regist(User user) {
        //注册使用字符缓冲输出流
        BufferedWriter bw=null;
        try {
            bw=new BufferedWriter(new FileWriter(file ,true));
            //固定一种格式
            bw.write(user.getUsername()+"="+user.getPassword());
            bw.flush();
            bw.newLine();
        } catch (IOException e) {
            System.out.println("用户注册失败");
        }finally{
            //针对流对象非空判断
            if(bw!=null){
                try {
                    bw.close();
                } catch (IOException e) {
                    System.out.println("用户注册释放资源失败");
                }
            }
        }

    }

}

用户测试类

package org.westos_11_User;

import java.util.Scanner;

/**
 * 用户测试类
 * @author 小鑫
 *
 */
public class UserTest {

    public static void main(String[] args) {

        while(true){
            //选择界面
            System.out.println("--------欢迎光临--------");
            System.out.println("1 注册");
            System.out.println("2 登录");
            System.out.println("3 退出");

            //创建键盘录入对象
            Scanner sc = new Scanner(System.in);
            //调用功能
            UserDaoImpl ud = new UserDaoImpl();
            System.out.println("请选择");
            String choice = sc.nextLine();

            switch(choice){
            case "1":
                //注册界面
                System.out.println("------注册界面------");
                System.out.println("请输入用户名");
                String newUsername = sc.nextLine();
                System.out.println("请输入密码");
                String newPassword = sc.nextLine();

                //创建用户对象,封装用户名和密码
                User u = new User();
                u.setUsername(newUsername);
                u.setPassword(newPassword);
                //调用东功能
                ud.regist(u);
                System.out.println("恭喜您,注册成功");
                break;

            case "2":
                //登陆界面
                System.out.println("------登陆界面------");
                System.out.println("请输入用户名:");
                String username = sc.nextLine() ;
                System.out.println("请输入密码:");
                String password = sc.nextLine() ;

                //调用功能
                boolean flag = ud.isLogin(username, password);
                if(flag){
                    System.out.println("登录成功");
                    System.exit(0);         
                }else{
                    System.out.println("登录失败,用户名或密码不正确");
                }
                break;

            case "3":
                //退出界面
                System.out.println("谢谢使用,欢迎下次光临");
                System.exit(0);
                break;
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值