17Java语法回顾之多线程

Java语法回顾之多线程


读了那么多年的书让我明白一个道理。人要稳重,不要想到啥就做啥。做一行越久即使你不会,几年之后慢慢的你也会了,加上一点努力你或许你能成为别人眼中的专家。

多线程简介

/*
 * 多线程:就是指应用程序有多条执行路径。
 *      进程:正在运行的应用程序。
 *      线程:进程的执行单元,一条执行路径。
 * 
 * 我们如何实现多线程程序呢?
 * 由于线程是依赖于进程存在,而进程是由操作系统创建的,并且java语言是不能直接调用操作系统的功能。
 * 所以,为了方便对多线程程序的时候,java就提供了线程的API对应的类。
 * 
 * 线程类:Thread
 * 
 * 通过查看API,我们知道创建线程的方式有2种。
 * 方式1:继承Thread类。
 *      A:定义一个类继承Thread类。
 *      B:子类要重写Thread类的run()方法。
 *      C:让线程启动并执行。
 *          注意:启动线程并执行,是不能使用run()方法的。这个时候,必须使用另外的一个方法。
 *                      这个方法名是start()。这个方法其实做了两件事情,第一,让线程启动。第二,自动调用run()方法。
 * 
 * 为什么要使用线程?以及什么时候使用?
 * 为了提高效率才使用。
 * 只有当要操作的代码的内容比较多(耗时),循环次数较多这样的情况才使用。
 */

多线程简单代码测试

public class MyThread extends Thread {

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

Test类

public class ThreadDemo {
    public static void main(String[] args) {
        MyThread my1 = new MyThread();
        MyThread my2 = new MyThread();

        my1.setName("线程1");
        my2.setName("线程2");

        // my.run();
        // my.run();

        // 同一个线程对象连续两次start,报错:IllegalThreadStateException
        // 表示该线程的状态有问题。
        // my.start();
        // my.start();
        my1.start();
        my2.start();
    }
}

多线程的第二种实现方式

/*
 * 方式2:
 *      A:创建一个类实现Runnable接口
 *      B:重写run()方法
 *      C:创建类的实例
 *      D:把类的实现作为Thread的构造参数传递,创建Thread对象
 * 
 * 既然有了继承Thread类的方式,为什么还要有实现Runnable接口的方式?
 * A:避免的单继承的局限性
 * B:实现接口的方式,只创建了一个资源对象,更好的实现了数据和操作的分离。
 * 一般我们选择第二种方式。
 */

多线程的第二种实现方式代码测试

public class MyThreadTest {

    public static void main(String[] args) {
        xiaThread xiaThread = new xiaThread();
        // xiaThread.start();  ???
        // 实现了Runnable接口的类没有start()方法,而我们启动线程必须调用start()方法。
        // 又由于,start()方法只有Thread类有。所以,我们就考虑这个把该类转换成Thread类。
        Thread thread = new Thread(xiaThread);
        Thread thread2 = new Thread(xiaThread);
        thread.setName("线程1***");
        thread2.setName("线程2###");
        thread.start();
        thread2.start();
    }
}
class xiaThread implements Runnable{

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

}

用多线程模拟火车站窗口售票

/*
     * 多线程程序的场景:
     *      窗口卖火车票
     * 
     * 有一趟火车:k261(北京西-十堰),票不多了,还剩200张。有4个窗口卖票。
     * 使用多线程,模拟窗口卖票。
     *      
     * 两种方式实现:
     * 方式1:继承Thread类
     * 方式2:实现Runnable接口
     */

用多线程模拟火车站窗口售票代码测试

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        HuochePiao huochePiao = new HuochePiao();
        Thread thread1 = new Thread(huochePiao);
        Thread thread2 = new Thread(huochePiao);
        Thread thread3 = new Thread(huochePiao);
        Thread thread4 = new Thread(huochePiao);
        thread1.setName("窗口一:");
        thread2.setName("窗口二:");
        thread3.setName("窗口三:");
        thread4.setName("窗口四:");
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
    }

}
class HuochePiao implements Runnable{
    public static int piao = 100;
    @Override
    public void run() {
        while (true) {
            System.out.println(Thread.currentThread().getName()+"正在售出第"+piao--+"张票");
            //如果没有票就跳出循环
            if (piao==0) {
                break;
            }
        }
    }

}

改写模拟火车站窗口售票

/*
 * 目前这个代码是符合真实的卖票程序。
 * 但是,有问题,居然出现了负数票的情况。
 * 那么,产生的原因是什么呢?
 *      线程的随机性和延迟性,导致了线程访问共享数据出现了问题。
 * 怎么解决呢?
 */

改写模拟火车站窗口售票代码测试

public class MyRunable {
    public static void main(String[] args) {
        XiaRunable xiaRunable = new XiaRunable();
        Thread thread1 = new Thread(xiaRunable);
        Thread thread2 = new Thread(xiaRunable);
        Thread thread3 = new Thread(xiaRunable);
        Thread thread4 = new Thread(xiaRunable);
        thread1.setName("窗口1:");
        thread2.setName("窗口2:");
        thread3.setName("窗口3:");
        thread4.setName("窗口4:");
        thread1.start();
        thread2.start();
        thread3.start();
        thread4.start();
    }
}

class XiaRunable implements Runnable {
    private static int piao = 100;
    @Override
    public void run() {
        while(true){
            //t1,t2,t3,t4过来了
            //锁对象的状态:开,关  我们需要添加一把锁,当我在操作的适合,我不允许其他线程进来
            synchronized (this) {
                if (piao > 0) {
                    //t1首先抢到了CPU的执行权,接着,进行了判断,发现是满足条件的,就进来了
                    //t2就抢到了,也进行了判断,发现还是满足,也就进来了
                    //t3抢到了,也进行了判断,发现还是满足,也就进来了
                    //t4抢到了,也进行了判断,发现还是满足,也就进来了
                    try {
                        //如果线程在这里睡着的话
                        //t1睡着了
                        //t2睡着了
                        //t3睡着了
                        //t4睡着了
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + "正在售票第" + piao-- + "张");
                }
            }
        }
    }
}

线程间的通信

/**
 * 线程间的通信问题
 * Created by xwf on 16/1/14.
 * <p/>
 * 需求:以学生作为资源举例。
 * 学生是资源,我们就可以对学生的属性进行赋值,也可以获取学生的属性值使用。
 * <p/>
 * 那么,我们要写那些内容呢?
 * 学生类:
 * 设置学生属性的类:
 * 获取学生属性的类:
 * 测试类:
 */

 /* 
 * 测试结果问题就产生了:
 *      出现了:
 *          林青霞 23
 *          宝宝 26
 */

线程间的通信代码测试

public class MyStudentThreader {
    public static void main(String[] args) {
        //为了使用同一个学生对象
        MyStudentTest myStudentTest = new MyStudentTest();
        //线程1 set 都是同一个对象
        SetMyStudent setMyStudent = new SetMyStudent(myStudentTest);
        //线程2 get 都是同一个对象
        GetMyStudent getMyStudent = new GetMyStudent(myStudentTest);
        Thread setThread = new Thread(setMyStudent);
        Thread getThread = new Thread(getMyStudent);
        setThread.start();
        getThread.start();
    }
}

class GetMyStudent implements Runnable {
    private MyStudentTest mst;

    public GetMyStudent(MyStudentTest mst) {
        this.mst = mst;
    }

    @Override
    public void run() {
        while (true) {
            System.out.println(mst.name + "*****" + mst.age);
        }
    }
}

class SetMyStudent implements Runnable {
    private MyStudentTest mst;

    @Override
    public void run() {
        int x = 0;
        while (true) {
            if (x % 2 == 0) {
                mst.name = "林青霞";
                mst.age = 26;
            } else {
                mst.name = "宝宝";
                mst.age = 23;
            }
            x++;
        }
    }

    public SetMyStudent(MyStudentTest mst) {
        this.mst = mst;
    }

}

class MyStudentTest {
    String name;
    int age;
}

线程间通信问题分析及解决方法

/* 既然问题出现了,我们先分析问题什么有这个问题,然后再解决问题。
 * 问题是由于线程的随机性产生的问题。
 * 
 * 然后我们在回到上午给大家的那个总结:
 *      A:是否有共享数据
 *      B:是否有多条语句操作共享数据
 *      C:是否在多线程环境中
 * 
 * 出问题的原因我们知道了,那么怎么解决呢? 
 * 用同步解决。
 * 我们把setStudent给加同步了,但是,还是有问题。原因是需要对多个线程都要加同步。
 * 我给两个操作都加同步了,还是出问题,这一次的原因是:两种操作的锁对象不一致。
 * 当我们把所有的操作都加同步,并且锁用同一个以后,我们的数据就没有问题了。

线程间通信问题分析及解决方法代码测试

//在set和get2个类中添加锁机制并使用同一个锁对象
class GetMyStudent implements Runnable {
    private MyStudentTest mst;

    public GetMyStudent(MyStudentTest mst) {
        this.mst = mst;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (mst) {
                System.out.println(mst.name + "*****" + mst.age);
            }
        }
    }
}

class SetMyStudent implements Runnable {
    private MyStudentTest mst;

    @Override
    public void run() {
        int x = 0;
        while (true) {
            synchronized (mst) {
                if (x % 2 == 0) {
                    mst.name = "林青霞";
                    mst.age = 26;
                } else {
                    mst.name = "宝宝";
                    mst.age = 23;
                }
                x++;
            }
        }
    }

    public SetMyStudent(MyStudentTest mst) {
        this.mst = mst;
    }

}

sleep和wait()的区别

/*
 * 面试题:sleepwait()的区别?
 * wait():是Object类的方法,可以不用传递参数。释放锁对象。
 * sleep():是Thread类的静态方法,需要传递参数。不释放锁对象。
 * 
 */

线程的优先级

/*
 * 测试线程的优先级问题:
 *      线程默认优先级是5。范围是1-10。
 * 
 * public final int getPriority():获取线程优先级
 * public final void setPriority(int newPriority):更改线程的优先级。
 * 
 * 注意:优先级可以在一定的程度上,让线程获较多的执行机会。
 */

线程的优先级代码测试

public class MyThreaderTest {
    public static void main(String[] args){
        ThreaderTest threaderTest = new ThreaderTest();
        Thread thread1 = new Thread(threaderTest);
        Thread thread2 = new Thread(threaderTest);
        Thread thread3 = new Thread(threaderTest);
        thread1.setName("线程1:");
        thread2.setName("线程2:");
        thread3.setName("线程3:");
        //设置线程的优先级
        thread1.setPriority(10);

        thread1.start();
        thread2.start();
        thread3.start();

        //获取线程的优先级
        //可以看出线程的默认优先级是5 最大是10,最小事1
        System.out.println("线程1的优先级"+thread1.getPriority());
    }
}
备注:关于多线程,暂时之学习到此,以后开发需要用到更多的多线程技术,再系统的学习多线程并发技术
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值