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()的区别
/*
* 面试题:sleep和wait()的区别?
* 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());
}
}